What is ndtv-d3?

The ndtv-d3 project is a network animation player for the ndtv R package. It makes it possible to view and share interactive network animations in a modern web browser without needing to install any external tools for rendering video.

Quick start: Display movie in a web browser

Load the library

library(ndtv)

Load an example data set in networkDynamic format

data(short.stergm.sim)

Render the animation as an html file, open it in an external browser window. Pass in the plot command to include labels for the vertices.

render.d3movie(short.stergm.sim,displaylabels=TRUE)

This will call compute.animation to figure out the positions, and then export the animation as Javascript data embedded in an HTML file. The animation should launch in new browser window displaying the ndtv-d3 player app with the animation inside it.

Notice that you can zoom (with the mouse-wheel), pan (drag the background) and click on the vertices and edges to display their ids. Double clicking on a vertex will highlight that vertex and its neighbors.

In general, render.d3movie uses the same graphics control arguments as plot.network and operates similarly to render.animation. However, see ?render.d3movie for more detailed description of supported arguments, as they are not all fully supported at this time.

For more information on how to convert various types of data (lists of matrices, timed edge lists, etc) into networkDynamic objects, see the R help page ?networkDynamic and the associated networkDynamic package vignette browseVignettes(package='networkDynamic').

EpiModel simulation example + embedding reults in an rmarkdown document

For a more complex example, we can render the example data from one of Sam Jenness’ basic epidemic simulation models create the EpiModel package. The object is distributed with the package as an example data set. For this version we will also set the time aggregation intervals () and additional rendering parameters.

Load and configure data

# Load a toy epidemic simulation model created by EpiModel
data(toy_epi_sim)

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

# pre-compute the animation coordinates
compute.animation(toy_epi_sim, slice.par = slice.par)

Now we are ready to render out the animation.

Render animation output for inclusion in an Rmarkdown document

The ndtv-d3 player object can be rendered inside an iframe in the rmarkdown document. The render.d3movie command must have output.mod='inline' to tell it to spit out the content directly instead of saving it to an external HTML file. We also need to set the markdown chunk argument for to result='asis' so that Knitr will pass through the HTML from ndtv “as is” without modification.

We can pass in some standard network.plot commands, and a functional command to generate interactive html tooltips to be displayed when the vertices are clicked on.

The output will appear as blank pane in the RStudio viewer, but works fine when viewed in a browser (Chrome is best/fastest)

render.d3movie(
  toy_epi_sim,
  render.par = render.par,
  plot.par = plot.par,
  vertex.cex = 0.9,
  vertex.col = "ndtvcol",
  edge.col = "darkgrey",
  vertex.border = "lightgrey",
  displaylabels = FALSE,
  vertex.tooltip = function(slice){paste('name:',slice%v%'vertex.names','<br>',
                                         'status:', slice%v%'testatus')},
  output.mode='inline')

The animation will show the vertices changing color as the “infection” gradually spreads across the network. Clicking on a vertex will give the its ID and infection status.

Save HTML+SVG movie output in a file for online embedding

There are additional output options to support saving and distributing the network animation.

Basic web embedding (i.e. blog post)

Perhaps you are working on a blog post or webpage and you would like to embed a network movie in it. Probably the best way to do this is to render out the movie HTML+SVG into a file, upload that to your server, and then include the page inside an iframe HTML tag.

The command below sets a specific file name (instead of tempfile()), avoids automatically opening the file in the web browser, and specifies that the Javascript source files should not be embedded and should instead load be loaded remotely. (This means the file size will be much smaller, of course a network connection will be necessary to view the web page)

render.d3movie(short.stergm.sim,filename='short.stergm.html',
                                launchBrowser=FALSE, 
                                script.type='remoteSrc')

After uploading the file, you could include it in your blog post with code like this:

Hey, this is a blog post, and below is a movie illustrating my dynamic network.
<iframe width=500 height=500 src='http://myserver.com/short.stergm.html'></iframe>

Advanced embedding (for web deveopers)

If you don’t want to use an iframe, and are building your own web page from scratch you should include the scripts in your page header and embed the animation in a regular div.

Here is an example template for a web-accessible page.

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <!-- css for styling the d3.slider lib -->
    <link rel='stylesheet' href='http://statnet.github.io/ndtv-d3/src/lib/d3.slider.css' />
    <!-- css for styling the ndtv-d3 render and components -->
    <link rel='stylesheet' href='http://statnet.github.io/ndtv-d3/src/css/styles.css' />
    <!-- minimized d3.js library -->
    <script src='http://d3js.org/d3.v3.min.js' charset='utf-8'></script>
    <!-- minimized jquery js library -->
    <script src='http://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js'></script>
    <!-- d3.slider.js library -->
    <script src='http://statnet.github.io/ndtv-d3/src/lib/d3.slider.js'></script>
    <!-- ndtv-d3 js code -->
    <script src='http://statnet.github.io/ndtv-d3/src/js/ndtv-d3.js'></script>
  </head>
  <body>
    <script>
      //INIT GRAPH DATA HERE
      var graphData = {};
      var options = {};
      //END GRAPH DATA INIT

      //Insert init JS Here
      $(function() {
        options.graphData = graphData;
        graph = new ndtv_d3(options);        
      })
    </script>
  </body>
</html>

In the example above, you would replace the value of the empty var graphData = {} with the JSON output produced by render.d3movie(myMovie,filename='myFile.json',output.mode = 'JSON') Additional examples for using and configuring the Javascript library are at https://github.com/statnet/ndtv-d3/.

Don’t forget that because the output is SVG and is part of the DOM, you can style it with CSS and directly interact with it using Javascript! The render.d3movie function includes special plot parameters for automatically adding arbitrary CSS class attributes to the graph to simplify CSS styling: vertex.css.class, edge.css.class, vertex.label.css.class.

Refining the layout

Just as for the render.animation function, if you want more control over the layout process, you can call compute.animation to first cache the layout positions in the network. For example, the MDSJ layout often gives much more stable layouts than the default Kamada-Kawai layout, and we can select it with the animation.mode argument (assuming you have java installed, it may prompt you to install MDSJ). We can also step through the layouts in reverse order to try and make it so the isolates won’t bounce around quite so much.

compute.animation(toy_epi_sim,animation.mode = 'MDSJ', chain.direction='reverse',verbose=FALSE)

Then we call the render command as before. But this time, lets render it in a browser.

render.d3movie(
  toy_epi_sim,
  render.par = render.par,
  plot.par = plot.par,
  vertex.cex = 0.9,
  vertex.col = "ndtvcol",
  edge.col = "darkgrey",
  vertex.border = "lightgrey",
  displaylabels = FALSE,
  vertex.tooltip = function(slice){paste('name:',slice%v%'vertex.names','<br>',
                                         'status:', slice%v%'testatus')})

Customizing the player

As the help page ?render.d3movie indicates, there are several options than can be passed in to control the behavior of the player in the web browser via the d3.options argument list. For example, we could set it to starting playing the movie immediately when the page loads (animateOnLoad), speed up the animation (animationDuration), and hide the timeline-slider controls (slider) in favor of just displaying the slice time in the lower left corner.

render.d3movie(
  toy_epi_sim,
  d3.options=list(animateOnLoad=TRUE,animationDuration=100,slider=FALSE,debugFrameInfo=TRUE),
  render.par = render.par,
  plot.par = plot.par,
  vertex.cex = 0.9,
  vertex.col = "ndtvcol",
  edge.col = "darkgrey",
  vertex.border = "lightgrey",
  displaylabels = FALSE,
  vertex.tooltip = function(slice){paste('name:',slice%v%'vertex.names','<br>',
                                         'status:', slice%v%'testatus')})

Or in the opposite direction, we can slow everything down, and increase the fraction of each time step used for “enter” and “exit” animations for edges and vertices. So in this version, you should be able to clearly see new edges fade in colored green, and the “dying” edges flash red before they they fade away.

render.d3movie(
  toy_epi_sim,
  d3.options=list(animationDuration=2000,enterExitAnimationFactor=0.5),
  render.par = render.par,
  plot.par = plot.par,
  vertex.cex = 0.9,
  vertex.col = "ndtvcol",
  edge.col = "darkgrey",
  vertex.border = "lightgrey",
  displaylabels = FALSE,
  vertex.tooltip = function(slice){paste('name:',slice%v%'vertex.names','<br>',
                                         'status:', slice%v%'testatus')})

Note that unless you explicitly disable it with durationControl=FALSE, there is an “Animation Duration” slider available in the menu in the upper right corner of the player which will allow the user to adjust the playback speed on the fly.

Interaction for static networks

Why should dynamic networks have all the fun? There are certainly situations where it is nice to be able to add the zooming, clickable inspection and annotation tools to display a static network on a web page. (See also the CRAN package networkD3 for similar functionality). If you pass render.d3movie a static network, it will go ahead and display it, but just hide the time slider and play controls (by default).

In the example below, we display one of the “Emergent Multi-Organizational” (?emon) networks of communication among organizations engaged in search and rescue activities. We will construct a tooltip label for the vertices from the vertex attribute data, size the vertices proportional to their membership and edges proportional to communication frequency. We also add some transparency to the colors to make it a bit prettier and more readable.

data(emon)
totalStaff<-emon[[5]]%v%'Volunteer.Staff'+emon[[5]]%v%'Paid.Staff'
sizeScale<-ifelse(is.na(totalStaff),1,totalStaff/100+1)
render.d3movie(emon[[5]],
    vertex.tooltip=paste("<strong>",emon[[5]]%v%'vertex.names',"</strong><br>",
      "Decision Rank Score:",emon[[5]]%v%'Decision.Rank.Score',"<br>",
      "Command Rank Score:",emon[[5]]%v%'Command.Rank.Score',"<br>",
      "Formalization:",emon[[5]]%v%'Formalization',"<br>",
      "Location:",emon[[5]]%v%'Location',"<br>",
      "Sponsorship:",emon[[5]]%v%'Sponsorship',"<br>"),
    vertex.cex=sizeScale,
    vertex.col=grDevices::adjustcolor(as.color(emon[[5]]%v%'Sponsorship'),alpha.f=0.5),
    edge.tooltip=paste('Frequency:',emon[[5]]%e%'Frequency'),
    edge.lwd='Frequency',
    edge.col='#00000055',
    output.mode='inline'
    )
## input network is not networkDynamic object and does not have temporal info so output animation controls disabled by default