ramnathv / htmlwidgets

HTML Widgets for R
http://htmlwidgets.org
Other
790 stars 208 forks source link

Graph update and force layout in sigma.js (shiny) #280

Open supersambo opened 7 years ago

supersambo commented 7 years ago

I'm trying to implement sigma.js in an R shiny application which allows the user to display smaller parts of a given (huge) graph. Given that the user should be able query the network freely the resulting graph must be layouted on the go, which is why I need to implement sigma.js force layout.

I started based on your provided example and I did so adding the plugin to the yaml file and adding sig.startForceAtlas2({worker: true, barnesHutOptimize: false}); to the renderValue function in sigma.js

HTMLWidgets.widget({

  name: "sigma",

  type: "output",

  factory: function(el, width, height) {

    // create our sigma object and bind it to the element
    var sig = new sigma(el.id);

    return {
      renderValue: function(x) {

        // parse gexf data
        var parser = new DOMParser();
        var data = parser.parseFromString(x.data, "application/xml");

        // apply settings
        for (var name in x.settings)
          sig.settings(name, x.settings[name]);

        // update the sigma object
        sigma.parsers.gexf(
          data,          // parsed gexf data
          sig,           // sigma object
          function() {
            // need to call refresh to reflect new settings and data
            sig.refresh();
          }
        );
            sig.startForceAtlas2({worker: true, barnesHutOptimize: false});
      },

      resize: function(width, height) {

        // forward resize on to sigma renderers
        for (var name in sig.renderers)
          sig.renderers[name].resize(width, height);
      },

      // Make the sigma object available as a property on the widget
      // instance we're returning from factory(). This is generally a
      // good idea for extensibility--it helps users of this widget
      // interact directly with sigma, if needed.
      s: sig
    };
  }
});

This works so far. However when I want update the graph new edges appear in the network but they do not affect the force algorithm isn't running on the new graph. I can see this because former isolated nodes that become connected through the update do not move and if the new graph is very different from the original one nodes do not move at all.

Here is an example of how I changed the server.R. ediaspora_reduced.gexf.xml is a copy of the original where I manually deleted some edges.

library(sigma)

gexf_file <- system.file("examples/ediaspora_reduced.gexf.xml", package = "sigma")

ui = shinyUI(fluidPage(
  checkboxInput("drawEdges", "Draw Edges", value = TRUE),
  checkboxInput("drawNodes", "Draw Nodes", value = TRUE),
  actionButton("go", "Go"),
  sigmaOutput('sigma')
))

server = function(input, output) {
  d = reactiveValues(gexf=gexf_file)

observeEvent(input$go, {
                 d$gexf <- system.file("examples/ediaspora.gexf", package = "sigma")
})

  output$sigma <- renderSigma(
    sigma(d$gexf, 
          drawEdges = input$drawEdges, 
          drawNodes = input$drawNodes)
  )
}

shinyApp(ui = ui, server = server)

How can I implement an update function so I can display new graphs with a query function?

(I've done something similar with NetworkD3 see here, however this time I'd really like to use sigma.js, since it's much more powerfull and feature-rich.)

JohnCoene commented 6 years ago

That is specific to sigma.js, you need to .refresh() the graph after adding edges or nodes