Skip to content
Advertisement

networkD3 in R – Freeze forceNetwork()

Is there any way to freeze the layout with forceNetwork() in the {networkD3} lib?

This is taking me a lot of time, because of the number of nodes that my network has. I just need to stop the animation. I found something here, but didn’t solve my problem.

Here is part of my code:

p <- forceNetwork(Links = links, 
                  Nodes = nodes, 
                  Source = 'source', 
                  Target = 'target', 
                  NodeID = 'name',
                  Group = 'group', 
                  Value = "value",
                  Nodesize = "size",
                  radiusCalculation = JS("d.nodesize"),
                  zoom = TRUE, 
                  arrows = FALSE,
                  linkWidth = JS("function(d){return d.value;}"),
                  linkDistance = JS("function(d){return d.value*10}"),
                  charge = gravity,
                  opacity = 0.95,
                  fontSize = 24,
                  linkColour = "#424242"
)

customJS <- 
  "function() { 
    d3.selectAll('.node text').style('fill', 'white').attr('stroke-width', '.1px').attr('stroke', '#3f3f3f');
    d3.select('body').style('background-color', '#15171a');
    d3.layout.force().tick();
    d3.layout.force().stop();
  }"


g <- htmlwidgets::onRender(p, customJS)
g

Answer

You could stop the simulation, run forward through the ticks without updating the positions (effectively the “animation”), and then restart the simulation so the nodes’ positions are updated…

library(networkD3)

p <-
  forceNetwork(
    Links = MisLinks,
    Nodes = MisNodes,
    Source = "source",
    Target = "target",
    Value = "value",
    NodeID = "name",
    Group = "group",
    opacity = 0.4,
    zoom = TRUE
  )

customJS <- '
  function() {
    simulation = this;
    simulation.stop();
    for (var i = 0; i < 300; ++i) simulation.tick();
    simulation.nodes().forEach( function(d,i) {
      d.cx = d.x;
      d.cy = d.y;
    });
    simulation.restart();
  }
'

htmlwidgets::onRender(p, customJS)

I’ve also been working on a successor to {networkD3} that can do this easily (although by default it uses canvas instead of SVG, and therefore it can handle much more data, even with the animation)…

library(network.r2d3)
url <- "https://gist.githubusercontent.com/mbostock/ad70335eeef6d167bc36fd3c04378048/raw/df541a01e850c6073ece4516fcd74ea1bae080ab/miserables.json"
force_network(url, plot_static = TRUE)
Advertisement