Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Dynamically adding nodes to Cytoscape

My company is building a graph-view editor for chatbots. We are using Cytoscape along with the cytoscape-cola extension to accomplish this. One of the issues we are facing is dynamically adding new nodes to the graph without them overlapping with existing nodes on the graph.

I have looked through previous similar questions(listed below) but to no avail:

Cytoscape - handle locked nodes

I tried the solution in there i.e. applying the layout only on the newly added nodes but they keep getting stacked in the centre of the screen.

Cytoscape - ignore locked nodes

I tried the solution mentioned in here but regardless of locking the nodes in one go i.e. cy.nodes().lock() or individually i.e. cy.nodes().forEach(node => node.lock()), the locked nodes still keep moving. Also interesting thing to note here is that when locking nodes individually, the newly added node(s) are also locked regardless of whether or not I am locking in the call above or not.

Cytoscape - dynamically add nodes without moving others

I tried this solution as well but the locked nodes still move and the complete layout is changed - sometimes altogether, sometimes just a little.

Code

This is currently what I am using to construct the graph:

const layoutConfig = {
    name: "cola",
    handleDisconnected: true,
    animate: true,
    avoidOverlap: true,
    infinite: false,
    unconstrIter: 1,
    userConstIter: 0,
    allConstIter: 1,
    ready: e => {
        e.cy.fit()
        e.cy.center()
    }
}
this.graph = Cytoscape({ ... })

this.layout = this.grapg.makeLayout(layoutConfig)

this.layout.run();

This is what I am using to add new node(s) to the graph:

const addElements = (elements: ElementSingular | ElementMultiple) => {
    this.graph.nodes().forEach(node => {
        node.lock();
    })

    this.graph.add(elements)

    this.layout = this.graph.makeLayout(layoutConfig)

    this.layout.on("layoutready", () => {
        this.nodes().forEach(node => {
            node.unlock();
        })
    })

    this.layout.run()

    this.graph.nodes().forEach(node => {
        node.unlock();
    })
}

I'd like to do one of the following:

  1. Understand what I am doing wrong if what I am trying to accomplish is possible but my code doesn't achieve it
  2. Understand why I would not be able to accomplish it i.e. the limitations that govern it
like image 773
iAMdifferent Avatar asked Oct 01 '19 07:10

iAMdifferent


People also ask

How do you align nodes in cytoscape?

11.3. The simplest method to manually organize a network is to click on a node and drag it. All of the selected nodes are moved together. In addition to the ability to click on a node and drag it to a new position, Cytoscape now has the ability to move nodes using the arrow keys on the keyboard.

What is passthrough mapping in cytoscape?

Passthrough MappingThe values of network column data are passed directly through to properties. A passthrough mapping is typically used to specify node/edge labels. For example, a passthrough mapping can label all nodes with their common gene names.

How do you select multiple nodes in cytoscape?

Hold left-click and drag to select multiple nodes · Issue #810 · cytoscape/cytoscape.


1 Answers

Edit: Is this what you were looking for? https://output.jsbin.com/hokineluwo

Edit: I didn't saw before, but you are also unlocking the nodes right after the layout call, Cola is async, the run only kicks-off the process. Remove that code and only use the layoutstop method.

I don't remember correctly, but i think that cola keeps moving the elements after the layoutready. From their code:

// trigger layoutready when each node has had its position set at least once

There is a layoutstop event that you could use (and cytoscape-cola uses too).

From the docs (emphasis is mine):

layoutready : when a layout has set initial positions for all the nodes (but perhaps not final positions)

layoutstop : when a layout has finished running completely or otherwise stopped running

I would try to remove that callback and inspect if it gives good results. Also, you should try to reproduce it here: http://jsbin.com/fiqugiq

It makes it easier for others (even the authors) to play with it and see if you have found a bug or not.

like image 180
Josejulio Avatar answered Nov 02 '22 20:11

Josejulio