rsnatemporalstatnet

Controlling dynamic vertex attributes using networkDynamic and/or ndtv


I am looking at how government agencies change over time. The plan is to use the ndtv package to visualise changes. I have an nodelist that lists vertex ids, agency name, node onset and node terminus:

nodelist <- read.csv("https://github.com/aterhorst/data/raw/master/nodelist.csv", header=T, stringsAsFactors = F)

and an edgelist showing onset, terminus of edges:

edgelist <- read.csv("https://github.com/aterhorst/data/raw/master/edgelist.csv", header=T, stringsAsFactors = F)

I can create a network object pretty easily:

nw <- network(edgelist,
              vertex.attr = nodelist[,c(1,2)],
              vertex.attrnames = c("vertex.id", "agency"), 
              directed = F)

nd <-networkDynamic(nw, 
                    edge.spells = edgelist[,c(3,4,2,1)],
                    vertex.spells=nodelist[,c(3,4,1)])

I can animate the network in terms of edges, vertices no problem:

reconcile.vertex.activity(nd, mode = "match.to.edges")

filmstrip(nd, 
          displaylabels = FALSE, 
          frames = 5, 
          slice.par = list(start = 2014, end = 2019, interval = 1, aggregate.dur = 1, rule = 'any'))

render.d3movie(nd,
               filename = "~/owncloud/longspine/data/animation.html",
               displaylabels = FALSE,
               # This slice function makes the labels work
               vertex.tooltip = function(slice) {paste("<b>Agency:</b>", (slice %v% "agency"))})

Essentially this shows how edges and vertices come and go over time. Next, I want to size vertices by agency budget. This changes from year to year. How should I do this? The online tutorials are a bit hard to intepret. In my example we have 217 agencies in total. Each would have an annual budget (if they exist as per onset, terminus in nodelist). Any tips or advice would be appreciated.


Solution

  • I managed to get something to work.

    require(sna)
    require(tsna)
    require(ndtv)
    require(networkDynamic)
    require(lubridate)
    
    nodelist <- read.csv("https://github.com/aterhorst/data/raw/master/nodelist.csv", header=T, stringsAsFactors = F)
    edgelist <- read.csv("https://github.com/aterhorst/data/raw/master/edgelist.csv", header=T, stringsAsFactors = F)
    nodelist_expanded <- read.csv("https://github.com/aterhorst/data/raw/master/nodelist_expanded.csv", header=T, stringsAsFactors = F)
    
    # onset date must be numeric (does not like date?)
    nodelist$onset <- year(nodelist$onset)
    nodelist$terminus <- year(nodelist$terminus)
    
    # colour nodes by portfolio type
    nodelist$col <- ifelse(nodelist$portfolio == T, "red", "blue")
    
    nodelist_expanded$onset <- year(nodelist_expanded$onset)
    nodelist_expanded$terminus <- year(nodelist_expanded$terminus)
    
    # scale attributes
    nodelist_expanded$log_appropriation <- log(nodelist_expanded$appropriation + 10) / 10
    nodelist_expanded$log_ext_revenue <- log(nodelist_expanded$ext_revenue + 10) / 10
    
    edgelist$onset <- year(edgelist$onset)
    edgelist$terminus <- year(edgelist$terminus)
    
    # create basic network object
    nw <- network(edgelist[,c(2,3)],
              vertex.attr = nodelist[,c(1:3,6)],
              vertex.attrnames = c("vertex.id", "agency", "portfolio", "col"),
              directed = F)
    
    # plot basic network object
    plot(nw, vertex.col = "col")
    
    # make dynamic network object
    nd <-networkDynamic(nw,
                        edge.spells = edgelist[,c(4,5,3,2)],
                        vertex.spells = nodelist_expanded[,c(6,7,1,8,9)],
                        create.TEAs = TRUE,
                        vertex.TEA.names = c("log_appropriation", "log_ext_revenue"))
    
    # reconcile things
    reconcile.vertex.activity(nd, mode = "match.to.edges")
    
    # make movie!
    render.d3movie(nd,
                   displaylabels = FALSE,
                   vertex.col = "col",
                   vertex.tooltip = function(slice) {
                 paste("<b>Agency:</b>", (slice %v% "agency"))})