plotly / react-cytoscapejs

React component for Cytoscape.js network visualisations

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

All nodes are accumulated in one position.

scnetrix opened this issue · comments

When creating a path using dagre, the whole nodes accumulate in one position. How can we set default positions for nodes ( Cytoscape js without react works fine) instead of setting position separately using position attribute for nodes.

const layout = {
name: "dagre",
rankDir: "LR"
}
pageData = < CytoscapeComponent
elements = {
CytoscapeComponent.normalizeElements({
nodes: nodess,
edges: edgess,
layout: layout,
})
}
pan = {
{
x: 200,
y: 200
}
}
autounselectify = {
true
}
userZoomingEnabled = {
false
}
boxSelectionEnabled = {
false
}
style = {
{
width: "1200px",
height: "1000px"
}
}
/>
return (
< div

{
pageData
}
< /div>
);

/------------------------------/
Expected Result
Expected Result

Current Result
Current-Result

I encountered something similar. I found a workaround but I don't know if it's a bandaid because I'm doing it wrong or not.

Effectively, I used the graph event hooks to call the layout function as nodes were added. Try this and see what works for you. Maybe it will uncover or yield insight into how it's meant to be done:

<CytoscapeComponent
  cy={cy =>
    cy.on('add', 'node', _evt => {
      cy.layout(layoutOptions).run()
      cy.fit()
    })
  } 
/>

Seems like this idea was repeated here: #43

Admittedly not obvious though

Seems like this code is needed when i tried to re-render a different graph on the same canvas. All my nodes are on the same position previously.

Adding the cy.on calls didn't solve the problem for me. I've tried putting a run on ready as well, and no good. Not really sure what else there is to try...

const layout = {
name: "dagre",
rankDir: "LR"
}
pageData = < CytoscapeComponent
elements = {
CytoscapeComponent.normalizeElements({
nodes: nodess,
edges: edgess,
layout: layout,
})
}

I'm confused why the layout is part of the CytoscapeComponent.normalizeElements call, it should be set next the elements as another property

I'm having the same problem, and just like eps-tvaughan, cy.on did not solve the problem for either.

Edit: it did work, I misspelled the cy prop

What worked really well for me is this:

                    cy.on('resize', _evt => {
                        cy.layout(layoutOptions).run()
                        cy.fit()
                    })

This will run the layout the first time it configures the size, which is apparently after the nodes have been added. This is way more performance friendly than running it on every node add.

I ended up using a different lightweight graph vis library and writing my own basic layout calculation. My graphs are pretty light (strictly less than 20 nodes) and I think ultimately cytoscape is probably overkill for what I'm doing.

commented

from a plotly component. works for me but its really not obvious to get here... thanks those pathfinders!

                <CytoscapeComponent
                    cy={cy =>
                        cy.on('add', 'node', _evt => {
                            cy.layout(layout).run()
                            cy.fit()
                        })
                    }
                    className='cyto-box'
                    elements={graphData}
                    layout={layout}
                    stylesheet={stylesheet}
                />

What worked really well for me is this:

                    cy.on('resize', _evt => {
                        cy.layout(layoutOptions).run()
                        cy.fit()
                    })

This will run the layout the first time it configures the size, which is apparently after the nodes have been added. This is way more performance friendly than running it on every node add.

Unfortunately I didn't have similar luck, however your comment inspired a simple workaround which was to only call layout and fit after all the changed elements had been added (i.e. run a counter in the add event handler and when it matches elements.length, then do the layout and fit).

edit: by similar luck, I mean I tried using resize and for my use case (changing elements from React set state), I didn't get the layout/fit calls expected.

Because my elements are fed into the parent component by a variable created with useState, what I'm doing is just running the .layout and .fit methods in a React.useEffect hook. The plus side is that this works. The downside is that the window spazzes a little bit when I change the data.

    React.useEffect(() => {
        if (cyRef.current !== null) {
            cyRef.current.layout(graphLayout).run()
            cyRef.current.fit()
        }
    })

    return <CytoscapeComponent elements={allElements}
                style={graphComponentStyle}
                stylesheet={graphStyleSheet}
                layout={graphLayout}
                cy={cy => {
                    cyRef.current = cy
                }}/>

To be clear, allElements is not the useState variable; the actual state variable is higher up, which is comprised of random JSON that from a server. I run some processing on the stateful variable to get allElements.

This worked for me... using the "dagre" layout

        cy={cy => {
            // The layout is set here. Otherwise, it doesn't
            // seem to respond well!
            cy.layout(settings[renderLayout]).run();
        }}