How to create a hierarchy - cytoscape.js

just started playing with cytoscape.js and the breathfirst layout. Looks like it will be a great library. I want to be able to create a layered or tree like layout, ideally being able to pin nodes to a level. Is there any suggestions on the correct layout to use or how to achieve it.
Does anyone know how to use the roots: ? I tried like this "roots: 'xyz'" where xyz is the id of the root node in my diagram.
Also I was trying to lock my root node like below using the position and locked attribute which did not seem to work.
{ data: { id: "XYZ", name: "XYZ", weight: 100, faveColor: "#F5A45D", faveShape: "triangle" , position: {x: 150, y: 10}, locked: true}},
If I can't get it to work my fall back will be to use graphviz to calculate the layout and position the nodes manually in code.

You can only specify elements as roots. I'll add the ability to use selector strings for 2.2.4:
https://github.com/cytoscape/cytoscape.js/issues/498
As for the layout itself, nodes are positioned based on edge direction hierarchy, so you can only guarantee the position of the specified root nodes. The rest fall underneath in the hierarchy.

Related

PyVis Graph shows some nodes colour as green and some as yellow even though the nodes are assigned with colour green

I have generated a PyVis graph but the graph output has just one problem and seems i can't find the reason and lost to no ideas anymore, i am not sure if it is a bug in PyVis drawing or I have made an error in generating the graph. Please advise, i am keen to know the cause here.
The PyVis graph I have generated contains 196 nodes and 367 edges exactly.
Of those 196 nodes, certain group of nodes are assigned with specific colours. About 42 nodes are assigned with colour "green" (using hex colour code #00ff00) and their shape has been changed to be a Square here for easy visual in an attempt to show my problem.
Of those 42 nodes, 13 of them are not showing green but instead show yellow as their colour, even though the source code still have those nodes colour as green (in hex code), however the visual shows yellow.
Below one line code is me trying to point to the source code line of one node and its color is set to #00ff00.
{"color": "#00ff00", "font": {"color": "white", "face": "Verdana", "size": 90}, "group": "gp_b", "id": "node__120", "label": "node__120", "level": 3, "shape": "square", "size": 500} ,
The graph's full html code example is provided here linked to jsfiddle, please see if you can help me locate the problem and a fix. Thanks in advance.
https://jsfiddle.net/shashi12345/2pf781ba/1/
Additional info:-
Basically, the graph is first created using Python. I used NetworkX version 2.8.5, added nodes and edges and their attributes, and then imported that into PyVis all within Python. PyVis version i am using is 0.2.1. And the graph is generated/saved as html file from PyVis.
The vis.js vis-network library requires groups to be defined in the options as descibred in the documentation here. All square nodes are added to a group named gp_b however this isn't present in the vis-network options. It is odd that this results in the behaviour being seen, but it could be resolved in a number of ways described below.
As per the PyVis documentation here the options passed to vis.js can be configured which as is needed for some options below.
Adding Group to Options
Adding the group gp_b to the options without any styling defined fixes the issue, for example:
var options = {
groups:{
useDefaultGroups: true,
gp_b:{ }
},
// Other options
}
Adding Group to Options With Styles
Alternatively the styling could be removed from the nodes and instead placed on the group, for example:
var options = {
groups:{
useDefaultGroups: true,
gp_b:{
color: '#00ff00'
}
},
// Other options
}
Removing Group from Nodes
The group could also be removed from the nodes, this way they are not expecing style information from the group and will just the color they have defined.

dagre network - duplicated edges

when having a n-n relationship, is it possible to avoid the duplicated edges ? I am using the dagre layout:
layout: {
name: 'dagre',
rankDir: 'LR'
}
https://jsfiddle.net/me2p3ok9/
I would like a single edge connecting william to kate, then a single line going to george and charlotte, splitting in two. Here a picture for reference:
is this possible ?
I found it : the taxi-direction has to be set in the same direction of the dagre (in my case rightward)
see updated fiddle. now the challenge will be to center the 3 nodes underneath

Cytoscape.js get node position from dagre layout

In order to make zigzag like edges I need to make some calculations and for that I need every node's position on the layout and I am having some trouble achieving that.
I am trying to get the node's position this way:
cy.$('#1891').position()
but no matter which id I use, I always get {x: 0, y: 0} values.
When I add an event like this:
cy.on('mouseover', 'node', function(evt){
var node = evt.target;
console.log(node.position());
});
I get every node's postion.
What would be the right way of getting every node's position from dagre layout?
I found the solution.
It was a silly mistake by me. I was trying to get the node's position before the layout was applied. Putting the cy.$('#1891').position(); after the layout.run(); did the trick.

Add compound node on demand cytoscape.js

I was wondering how feasible is to add some compound elements (nodes) "on the go".
Scenario:
I have a network with nodes from n1...n10 and edges. Depending on the button the user clicks, it redraws my network including nodes inside a compound node.
Example:
When you open the graph, you have n1..n10, without compounds, but when you click on a pre-defined button, my new graph now would be:
A new compound node with n1:n5 inside (parent), and the rest n6:n10 would stay the same (outside compound).
How feasible is it ?
I've tried :
cy.batchData({
"5": {
parent: "n0" // new element I added earlier
}});
to update my element id=5 to have n0 as parent, but it haven't worked.
The main idea is to represent data (graph) with biological insight, where the "new compound area" would be a pathway or a metabolic path (or whatever I want to represent there), one by one, so the visualization won't be a mess.
Thank you.
You can't change the parent field; it's immutable. You may have to remove the elements and add the second (resultant) graph via eles.remove() and cy.add() respectively.

ExtJS 4: Add children tree nodes to a non-Root node dynamically?

I am trying to add children tree nodes to a non-Root node dynamically when it's selected.
This is how I implemented it:
First, I populate my tree with a TreeStore then to dynamically add children tree nodes, I handle it on the itemexpand event in tree Controller.
//pThis is a NodeInterface obj of the selected node
itemexpand: function (pThis, pEOpts) {
//type is an attribute that I added so that I know what type of node that got selected
if (pThis.raw.type === 'Staff' && !pThis.hasChildNodes()) {
var staffNodeAry = [{text:"Teachers", type:"ChildStaff", leaf: false},
{text:"Principals", type:"ChildStaff", leaf: false}];
pThis.appendChild(staffNodeAry);
}
}
This worked quite good because I am able to see both "Teachers" and "Principals" node under "Staff" type but there are 2 issues that I found so far:
1) There's this error on the console:
Uncaught TypeError: Cannot read property 'internalId' of undefined
I don't know why but if anyone could enlighten that would be great.
2) When I expand either "Teachers" and "Principals", the NodeInterface obj that's returned by itemexpand has an undefined raw object.
So I couldn't do this: pThis.raw.type
From my understanding, I don't need to create a new TreeStore to add any new children nodes, I thought that by creating an array of objects that adhere to NodeInterface should be enough but I might be wrong.
If anyone could point me to the right direction, that would be great.
Handi
More info:
What I did was actually following the ExtJs 4 documentation so I believe this is a bug on ExtJs 4 framework.
I also tested this with Extjs-4.1.0-rc3 and it also produced the same error.
I have resolved this issue changing the event itemexpand with the event afteritemexpand. I have no documentation to justify this. The debugger says to me that the view listen for the itemexpand event and do something that goes wrong if add a node manually...
For the question number 2: you have no raw object because it is created by the reader of the store after the load operation. So if you add a node by hand the raw object does not exists.
http://docs.sencha.com/ext-js/4-1/#!/api/Ext.data.Model-property-raw
The documentation for .appendChild() functions says:
node : Ext.data.NodeInterface/Ext.data.NodeInterface[]
The node or Array of nodes to append
And you are trying to append an array of 2 objects, but they are not "NodeInterface" instances. So you should create them properly like so:
var nodeToAppend1 = pThis.createNode({text:"Teachers", type:"ChildStaff", leaf: false});
pThis.appendChild(nodeToAppend1);
I remember making the same mistake a year ago, so I hope this helps.
I think it happens because your Ext.TreePanel working asyncroniously. So add process is:
Append Child, add virtual child leaf to your tree, with red mark in corner
Call store's create api
Receive response, if it success=true, change with virtual
The goal of changing is set internakId property, so you can add new child only after this change happens. I think better is write some recursive function and bind it to store's added event
tree.getStore().on('update', addChild);
or
tree.getStore().load({
success: function() {
addChild()
});