`install.packages("ndtv")`

# 26 Dynamic Network Visualization

This tutorial demonstrates methods for dynamic visualization of the spread of infectious disease over networks using the `ndtv`

package for R. `ndtv`

is part of the larger `Statnet`

suite of software for the representation, modeling, and analysis of network data. It has been designed to work with network-based epidemic modeling data from `EpiModel`

.

## 26.1 Installation

We need to start by installing the `ndtv`

package. This package version has just been updated on CRAN. You can first start by trying:

If that does not work (because binaries for `ndtv`

may not yet be available on CRAN), you can try with:

```
# install this package in case you do not already have it installed
install.packages("remotes")
::install_github("statnet/ndtv", subdir = "ndtv") remotes
```

Then check the package version with, which should match the version number below.

```
library("ndtv")
packageVersion("ndtv")
```

`[1] '0.13.3'`

## 26.2 Setup

We start by loading `EpiModel`

. The `htmlwidgets`

library additionally allows for embedding `ndtv`

movies into RMarkdown HTML pages like this (you do not need to install/load it for this course but we need it to build this page).

```
library("EpiModel")
library("htmlwidgets")
```

In general, one primary goal of dynamic network visualization is to gain insight into how the structure of networks over time can influence transmission dynamics. This is different from estimating epidemic outcomes such as disease incidence or prevalence over time. The latter will typically require large networks (thousands of nodes) over large numbers of time steps (decades of time) with many hundreds or thousands of simulations. This allows for more accurate and stable estimation of outcome averages and spread. Dynamic visualization, on the other hand, usually only requires a single simulation of a small network size over a short number of time steps. That is because the visualization is meant to *demonstrate the mechanisms* rather than *estimate the effects.*

## 26.3 Model 1: Edges-Only

We start by setting a seed to ensure reproducible results. You can skip this to get different results from the tutorial page.

`set.seed(1234)`

### 26.3.1 Epidemic Model

This shows an SI epidemic in a closed population where the infection probability is 1, and we will start to build up complexity to the network model step-by-step. We start with a network of 100 nodes, with an edges-only model in the formation and dissolution.

```
<- network_initialize(n = 100)
nw <- ~edges
formation <- 40
target.stats <- dissolution_coefs(dissolution = ~offset(edges), duration = 20)
coef.diss <- netest(nw, formation, target.stats, coef.diss) est
```

For the epidemic model, we will replicate the poker chip example in which the transmission probability per act is 100%. We could modify this to be a lower (more relistic for most diseases) value, but we choose a high value here to show a speedy epidemic spread. We simulate the model over 25 time steps with a single simulation.

```
<- param.net(inf.prob = 1)
param <- init.net(i.num = 1)
init <- control.net(type = "SI", nsteps = 25, nsims = 1)
control <- netsim(est, param, init, control) sim
```

### 26.3.2 Network Visualization

`ndtv`

is an extension package in `Statnet`

that allows for dynamic visualization for networks over time. Because this involves animation processing, this may require some heavy duty computation.

#### 26.3.2.1 Extract and Process the Networks

First we need to extract the network objects from the larger `netsim`

object. This was one of the key uses of this object type first discussed in Session 3 today. Note that this object has details on the distinct time changes.

```
<- get_network(sim)
nw nw
```

```
NetworkDynamic properties:
distinct change times: 28
maximal time range: -Inf until Inf
Dynamic (TEA) attributes:
Vertex TEAs: testatus.active
Includes optional net.obs.period attribute:
Network observation period info:
Number of observation spells: 2
Maximal time range observed: 0 until 26
Temporal mode: discrete
Time unit: step
Suggested time increment: 1
Network attributes:
vertices = 100
directed = FALSE
hyper = FALSE
loops = FALSE
multiple = FALSE
bipartite = FALSE
net.obs.period: (not shown)
total edges= 104
missing edges= 0
non-missing edges= 104
Vertex attribute names:
active status testatus.active vertex.names
Edge attribute names:
active
```

Next, we need to add a time-varying nodal attribute to each network that we will animate. This will allow `ndtv`

to color the nodes by disease status over time. See the help documentation for `color_tea`

to see some of the options and details for this step.

`<- color_tea(nw, verbose = FALSE) nw `

#### 26.3.2.2 Revisiting Static Visualizations

Before we start making a movie with this updated network object, recall the types of static visualizations of the co-evolving dynamic network and epidemic data that are possible with `EpiModel`

. One approach is to extract and work with the transmission matrix within the `netsim`

object.

```
<- get_transmat(sim)
tm tm
```

```
# A tibble: 39 × 7
# Groups: at, sus [39]
at sus inf infDur transProb actRate finalProb
<dbl> <int> <int> <dbl> <dbl> <dbl> <dbl>
1 2 13 64 16 1 1 1
2 2 47 64 16 1 1 1
3 3 72 47 1 1 1 1
4 4 67 64 18 1 1 1
5 8 81 67 4 1 1 1
6 9 1 81 1 1 1 1
7 10 29 67 6 1 1 1
8 10 68 1 1 1 1 1
9 11 16 68 1 1 1 1
10 11 57 68 1 1 1 1
# ℹ 29 more rows
```

Next, there are three built-in visualizations for the transmission matrix, as shown here. Previously we converted the transmission matrix into a `phylo`

class object and plotted a phylogram with the `ape`

package. Here, we are showing that we can also plot this `transmat`

object directly as a phylogram, and also as two related formats. Each show the time-directed chain of transmissions over time, starting with an initial seed. The middle plot is a directed network (showing who infected whom, here in a single large component because there was one seed). The right plot is a “transmission timeline” that plots the temporal time (the 25 time steps in our model) against generation time for transmissions.

```
par(mfrow = c(1, 3), mar = c(3, 3, 2, 1))
plot(tm, style = "phylo")
plot(tm, style = "network", displaylabels = TRUE)
plot(tm, style = "transmissionTimeline")
```

Finally, with the updated `ndtv`

network object from above, we can plot a “proximity timeline” that shows the proximity of the nodes in directed temporal graph space, colored by disease status. Here the network is the full contact network, not just the transmission network of infected nodes. This helps identify the micro-outbreaks of infection that are occurring within sub-clusters of the network with greater closeness.

```
par(mfrow = c(1, 1), mar = c(3, 3, 2, 1))
proximity.timeline(nw,
vertex.col = "ndtvcol",
spline.style = "color.attribute",
mode = "sammon",
default.dist = 10,
chain.direction = "reverse")
```

#### 26.3.2.3 Dynamic Network Movie

There are lots of possibilities for how to model our networks over time. Here we animate the first 25 time steps of the simulation. To find out all the options, consult the main vignette for the `ndtv`

package.

```
<- list(start = 1, end = 25, interval = 1,
slice.par aggregate.dur = 1, rule = "any")
<- list(tween.frames = 10, show.time = FALSE)
render.par <- list(mar = c(0, 0, 0, 0)) plot.par
```

This step figures out where the nodes should be displayed in each animation frame. There are several dynamic layout options available, but we use the defaults here.

`compute.animation(nw, slice.par = slice.par, verbose = TRUE)`

Finally, we render the animation and save it out to an HTML file using d3 Javascript. This makes for nice-looking animations within webpages. See the `ndtv`

help for all the potential options in this step.

```
render.d3movie(
nw,render.par = render.par,
plot.par = plot.par,
vertex.cex = 0.9,
vertex.col = "ndtvcol",
edge.col = "darkgrey",
vertex.border = "lightgrey",
displaylabels = FALSE,
filename = paste0(getwd(), "/movie.html"))
```

To embed movies into an RMarkdown document like this, we can set the `output.mode`

accordingly.

```
render.d3movie(
nw,render.par = render.par,
plot.par = plot.par,
vertex.cex = 0.9,
vertex.col = "ndtvcol",
edge.col = "darkgrey",
vertex.border = "lightgrey",
displaylabels = FALSE,
output.mode = "htmlWidget")
```

## 26.4 Model 2: No Concurrency

Let’s return to the core network model and experiment with extra terms, and then run the movie again. Next we will add `concurrent`

term in the model to control the number of nodes with overlapping partnerships. For reference, the expected number of concurrent nodes is a function of a Poisson distribution with the parameter equal to the mean degree (which is `2 x edges/N`

):

`ppois(1, lambda = 0.8, lower.tail = FALSE) * 100`

`[1] 19.12079`

One helpful ERGM term is `concurrent`

. This is the number of nodes with degree of 2 or higher. From the target stats above, next we can add a value for `concurrent`

above or below the expected value of 19.1, and see how that plays out for our network movie. You may find that your model does not fit if the `concurrent`

target stat is too high. That’s because you can’t have a huge number of concurrent persons if the mean degree (related to concurrency) is 0.8. In other words, the model terms and associated target statistics must be compatible.

### 26.4.1 Epidemic Model

In this example, we select an extreme concurrency statistic of 0 (no nodes exhibit concurrency).

```
<- network_initialize(n = 100)
nw <- ~edges + concurrent
formation <- c(40, 0)
target.stats <- dissolution_coefs(dissolution = ~offset(edges), duration = 20)
coef.diss <- netest(nw, formation, target.stats, coef.diss) est
```

```
Warning: 'glpk' selected as the solver, but package 'Rglpk' is not available;
falling back to 'lpSolveAPI'. This should be fine unless the sample size and/or
the number of parameters is very big.
```

We use the same epidemic parameters as above, but you can experiment with these too now.

```
set.seed(12345)
<- param.net(inf.prob = 1)
param <- init.net(i.num = 1)
init <- control.net(type = "SI", nsteps = 25, nsims = 1)
control <- netsim(est, param, init, control) sim
```

### 26.4.2 Static Transmission Output

Let’s just look at what the static transmission outputs look like without network concurrency but with the same epidemic parameters. This network with much more sparse connectivity results in a transmission tree that is also sparser.

```
par(mfrow = c(1, 3), mar = c(3, 3, 2, 1))
<- get_transmat(sim)
tm plot(tm, style = "phylo")
plot(tm, style = "network", displaylabels = TRUE)
plot(tm, style = "transmissionTimeline")
```

### 26.4.3 Dynamic Network Movie

We follow the same steps to make the movie. Notice here that nearly all nodes are connected within a dyad, and therefore that no concurrency implies few isolates given this relatively high mean degree (0.8). In fact, the logical maximum mean degree in a network with no concurrency would be 1.0. Notice how this “serial monogamy” constrains the speed of epidemic spread.

```
<- get_network(sim)
nw <- color_tea(nw, verbose = FALSE)
nw compute.animation(nw, slice.par = slice.par)
render.d3movie(
nw,render.par = render.par,
plot.par = plot.par,
vertex.cex = 0.9,
vertex.col = "ndtvcol",
edge.col = "darkgrey",
vertex.border = "lightgrey",
displaylabels = FALSE,
filename = paste0(getwd(), "/movie.html"))
```

## 26.5 Model 3: Relational Duration

One feature of network models is to represent persistent relationships, in which there are repeated contacts between the same set of persons over time. This involves modeling the incident formation and persistence of edges over time. We can also model the extremes of relational duration to see its impact on epidemic potential.

### 26.5.1 Model 3a: Very Long Durations

Here we use the same model as Model 1, but set the duration to 100,000 time steps. This effectively makes all edges fixed over the 25 simulation time steps.

```
<- network_initialize(n = 100)
nw <- ~edges
formation <- 40
target.stats <- dissolution_coefs(dissolution = ~offset(edges), duration = 1e5)
coef.diss <- netest(nw, formation, target.stats, coef.diss) est
```

We use the same epidemic parameters as above.

```
<- param.net(inf.prob = 1)
param <- init.net(i.num = 1)
init <- control.net(type = "SI", nsteps = 25, nsims = 1)
control <- netsim(est, param, init, control) sim
```

We follow the same steps to make the movie. Nothing much happening, even with a transmission probability of 100%.

```
<- get_network(sim)
nw <- color_tea(nw, verbose = FALSE)
nw compute.animation(nw, slice.par = slice.par)
render.d3movie(
nw,render.par = render.par,
plot.par = plot.par,
vertex.cex = 0.9,
vertex.col = "ndtvcol",
edge.col = "darkgrey",
vertex.border = "lightgrey",
displaylabels = FALSE,
filename = paste0(getwd(), "/movie.html"))
```