How to create layers with cytoscape concentric layout - javascript

I tried to create a inner and outer layer with the concentric layout.
But I don't get it to work.
This is how it looks for me:
The inner and outer nodes get mixed up.
And this is what I have expected:
My data:
{
data: [
{data: {
id: 'innerA', level: 1 },
group: 'nodes'
},
....
{data: {
id: 'outA', level: 2 },
group: 'nodes'
},
....
{
data: { source: 'innerA', target: 'outA' },
group: 'edges',
},
....
],
}
And my layout
layout: {
concentric: function( node ){
return node.data("level");
},
levelWidth: function( ){
return 2;
},
name: 'concentric',
minNodeSpacing: 50,
}
}
From what I have expected the concentric function in the layout, would assign the nodes
depending on the layer attribute in the node.
Hope someone has an idea.
Thank you in advance.

First of all, layout places higher level nodes towards the center, therefore your inner nodes should have level 2, while outer ones should have level 1. Secondly, I don't know how levelWidth option works, but using default value instead of 2 works.
var cy = window.cy = cytoscape({
container: document.getElementById('cy'),
style: [{
selector: 'node',
css: {
'content': 'data(id)'
}
},
{
selector: 'edge',
css: {
'curve-style': 'straight',
}
}
],
elements: [
{data: {
id: 'innerA', level: 2 },
group: 'nodes'
},
{data: {
id: 'innerB', level: 2 },
group: 'nodes'
},
{data: {
id: 'innerC', level: 2 },
group: 'nodes'
},
{data: {
id: 'innerD', level: 2 },
group: 'nodes'
},
{data: {
id: 'outA', level: 1 },
group: 'nodes'
},
{data: {
id: 'outB', level: 1 },
group: 'nodes'
},
{data: {
id: 'outC', level: 1 },
group: 'nodes'
},
{data: {
id: 'outD', level: 1 },
group: 'nodes'
},
{data: {
id: 'outE', level: 1 },
group: 'nodes'
},
{data: {
id: 'outF', level: 1 },
group: 'nodes'
},
{data: {
id: 'outG', level: 1 },
group: 'nodes'
},
{data: {
id: 'outH', level: 1 },
group: 'nodes'
},
{
data: { source: 'innerA', target: 'outA' },
group: 'edges',
},
{
data: { source: 'innerB', target: 'outC' },
group: 'edges',
},
{
data: { source: 'innerC', target: 'outE' },
group: 'edges',
},
{
data: { source: 'innerD', target: 'outG' },
group: 'edges',
},
],
layout: {
name: 'concentric',
concentric: function( node ){
return node.data("level");
},
minNodeSpacing: 50
}
});
body {
font: 14px helvetica neue, helvetica, arial, sans-serif;
}
#cy {
height: 95%;
width: 95%;
left: 0;
top: 0;
position: absolute;
}
<html>
<head>
<meta charset=utf-8 />
<meta name="viewport" content="user-scalable=no, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, minimal-ui">
<script src="https://unpkg.com/cytoscape#3.10.0/dist/cytoscape.min.js">
</script>
</head>
<body>
<div id="cy"></div>
</body>
</html>

Related

how to reverse a collection in cytoscape.js

I have a collection of elements (created by using pathTo from the dijkstra function).
I need to reverse elements of this collection, for instance I want to transform
[14, 2, 37, 4, 5] into [5, 4, 37, 2, 14].
I tried using the filter function as per below but to no success. Does anyone know how to reverse a collection (not an array)?
path = dijkstraDiverse.pathTo(cy.$id('5'));
newpath = path.filter(function(ele, i, eles) {
return eles[path.length - 1 - i];
});
I used the sort function and just reversed the collection that way. The important part is using -1 as the sorting metric, that way everything is simply reversed. I added some visual clarification derived from this BFS example:
var cy = (window.cy = cytoscape({
container: document.getElementById("cy"),
boxSelectionEnabled: false,
autounselectify: true,
style: [{
selector: "node",
css: {
content: "data(id)",
"text-valign": "center",
"text-halign": "center",
"height": "60px",
"width": "60px",
"border-color": "black",
"border-opacity": "1",
"border-width": "10px"
}
},
{
selector: "edge",
css: {
"label": "data(weight)",
"target-arrow-shape": "triangle"
}
},
{
selector: ".highlight",
css: {
'background-color': '#61bffc',
'line-color': '#61bffc',
'target-arrow-color': '#61bffc',
'transition-property': 'background-color, line-color, target-arrow-color',
'transition-duration': '0.5s'
}
},
{
selector: ".old",
css: {
'background-color': '#ff6e63',
'line-color': '#ff6e63',
'target-arrow-color': '#ff6e63',
'transition-property': 'background-color, line-color, target-arrow-color',
'transition-duration': '0.5s'
}
}
],
elements: {
nodes: [{
data: {
id: "n0"
}
},
{
data: {
id: "n1"
}
},
{
data: {
id: "n2"
}
},
{
data: {
id: "n3"
}
},
{
data: {
id: "n4"
}
},
{
data: {
id: "n5"
}
},
{
data: {
id: "n6"
}
},
{
data: {
id: "n7"
}
},
{
data: {
id: "n8"
}
},
{
data: {
id: "n9"
}
},
{
data: {
id: "n10"
}
},
{
data: {
id: "n11"
}
},
{
data: {
id: "n12"
}
},
{
data: {
id: "n13"
}
},
{
data: {
id: "n14"
}
},
{
data: {
id: "n15"
}
},
{
data: {
id: "n16"
}
}
],
edges: [{
data: {
source: "n0",
target: "n1",
weight: 1
}
},
{
data: {
source: "n1",
target: "n2",
weight: 11
}
},
{
data: {
source: "n1",
target: "n3",
weight: 12
}
},
{
data: {
source: "n2",
target: "n7",
weight: 2
}
},
{
data: {
source: "n2",
target: "n11",
weight: 3
}
},
{
data: {
source: "n2",
target: "n16",
weight: 1
}
},
{
data: {
source: "n3",
target: "n4",
weight: 32
}
},
{
data: {
source: "n3",
target: "n16",
weight: 7
}
},
{
data: {
source: "n4",
target: "n5",
weight: 6
}
},
{
data: {
source: "n4",
target: "n6",
weight: 4
}
},
{
data: {
source: "n6",
target: "n8",
weight: 11
}
},
{
data: {
source: "n8",
target: "n9",
weight: 12
}
},
{
data: {
source: "n8",
target: "n10",
weight: 1
}
},
{
data: {
source: "n11",
target: "n12",
weight: 1
}
},
{
data: {
source: "n12",
target: "n13",
weight: 2
}
},
{
data: {
source: "n13",
target: "n14",
weight: 3
}
},
{
data: {
source: "n13",
target: "n15",
weight: 5
}
}
]
},
layout: {
name: "dagre",
padding: 5
}
}));
cy.ready(function() {
const dijkstra = cy.elements().dijkstra(
"#n0",
function(edge) {
const weight = edge.data("weight");
return weight;
}
);
const oldPath = dijkstra.pathTo(cy.$("#n10"));
console.log(oldPath);
const newPath = oldPath.sort(function(a, b) {
return -1;
});
console.log(newPath);
let i = 0;
let j = 0;
let highlightPath = newPath;
let highlightNextEle = function() {
if (i < highlightPath.length) {
if (j == 0) {
highlightPath[i].addClass("highlight");
} else {
//highlightPath[i].removeClass("highlight");
highlightPath[i].addClass("old");
}
i++;
setTimeout(highlightNextEle, 1000);
} else if (i == highlightPath.length && j !== 1) {
i = 0;
j = 1;
highlightPath = oldPath;
setTimeout(highlightNextEle, 1000);
}
};
// kick off first highlight
highlightNextEle();
});
body {
font: 14px helvetica neue, helvetica, arial, sans-serif;
}
#cy {
height: 100%;
width: 100%;
left: 0;
top: 0;
float: left;
position: absolute;
}
<html>
<head>
<meta charset=utf-8 />
<meta name="viewport" content="user-scalable=no, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, minimal-ui">
<script src="https://unpkg.com/cytoscape#3.3.0/dist/cytoscape.min.js">
</script>
<script src="https://unpkg.com/jquery#3.3.1/dist/jquery.js"></script>
<!-- cyposcape dagre -->
<script src="https://unpkg.com/dagre#0.7.4/dist/dagre.js"></script>
<script src="https://cdn.rawgit.com/cytoscape/cytoscape.js-dagre/1.5.0/cytoscape-dagre.js"></script>
</head>
<body>
<div id="cy"></div>
</body>
</html>

Compound nodes overlap while using grid layout in cytoscape.js

I am using cytoscape.js for my visualization project in which I have to show a Hierarchical structure with compound nodes.
So I initially used Cose-Bilkent layout which worked like a charm but the requirement is that all the child nodes of a parent must be in a single row. So I tried to tweak around a bit but couldn't get the exact result.
Then I tried to use grid layout by giving hardcoded row and column numbers and I got the exact result but as my data is dynamic I realized its difficult to assign row numbers and column numbers on my own.
Here is the data I used,
elements: [ // list of graph elements to start with
{ // node a
data: { id: 'X1', label: 'X1'}
},
{
data: { id: 'X2', label: 'X2'}
},
{
data: { id: 'X3', label: 'X3'}
},
{
data: { id: 'X4', label: 'X4'}
},
{
data: { id: 'X5', label: 'X5'}
},
{
data: { id: 'X6', label: 'X6'}
},
{
data: { id: 'X7', label: 'X7'}
},
{
data: { id: 'X8', label: 'X8'}
},
{
data: { id: 'X9', label: 'X9'}
},
{
data: { id: 'X10', label: 'X10'}
},
{
data: { id: 'X1e1',label: 'e1', parent: 'X1', row: '1' ,col: '1'}
},
{
data: { id: 'X1e5',label: 'e5', parent: 'X1', row: '1',col: '2'}
},
{
data: { id: 'X1e6',label: 'e6', parent: 'X1', row: '1',col: '3'}
},
{
data: { id: 'X2e2',label: 'e2', parent: 'X2', row: '3',col: '1'}
},
{
data: { id: 'X2e3',label: 'e3', parent: 'X2', row: '3',col: '2'}
},
{
data: { id: 'X3e4',label: 'e4', parent: 'X3', row: '4',col: '1'}
},
{
data: { id: 'X4e5',label: 'e5', parent: 'X4', row: '2',col: '1'}
},
{
data: { id: 'X4e6',label: 'e6', parent: 'X4', row: '2',col: '2'}
},
{
data: { id: 'X5e7',label: 'e7', parent: 'X5', row: '7',col: '1'}
},
{
data: { id: 'X6e8',label: 'e8', parent: 'X6', row: '5',col: '1'}
},
{
data: { id: 'X6e9',label: 'e9', parent: 'X6', row: '5',col: '2'}
},
{
data: { id: 'X7e10',label: 'e10', parent: 'X7', row: '7',col: '2'}
},
{
data: { id: 'X7e11',label: 'e11', parent: 'X7', row: '7',col: '3'}
},
{
data: { id: 'X7e12',label: 'e12', parent: 'X7', row: '7',col: '4'}
},
{
data: { id: 'X8e13',label: 'e13', parent: 'X8', row: '6',col: '1'}
},
{
data: { id: 'X8e14',label: 'e14', parent: 'X8', row: '6',col: '2'}
},
{
data: { id: 'X8e15',label: 'e15', parent: 'X8', row: '6',col: '3'}
},
{
data: { id: 'X8e16',label: 'e16', parent: 'X8', row: '6',col: '4'}
},
{
data: { id: 'X9e17',label: 'e17', parent: 'X9', row: '8',col: '1'}
},
{
data: { id: 'X10e18',label: 'e18', parent: 'X10', row: '8',col: '2'}
},
{
data: { id: 'X1e5X4e5', source:'X1e5', target:'X4e5'}
},
{
data: { id: 'X1e6X4e6', source:'X1e6', target:'X4e6'}
},
{
data: { id: 'X1e1X2', source:'X1e1', target:'X2'}
},
{
data: { id: 'X2e3X3', source:'X2e3', target:'X3'}
},
{
data: { id: 'X4e5X5', source:'X4e5', target:'X5'}
},
{
data: { id: 'X4e6X6', source:'X4e6', target:'X6'}
},
{
data: { id: 'X6X8e16', source:'X6', target:'X8e16'}
},
{
data: { id: 'X6e9X8', source:'X6e9', target:'X8'}
},
{
data: { id: 'X6e8X7', source:'X6e8', target:'X7'}
},
{
data: { id: 'X6X7e12', source:'X6', target:'X7e12'}
}
]
and layout
layout:{
name: 'grid',
fit: true,
position: function( node ){ return {row:node.data('row'), col:node.data('col') }}
}
And here is the result I got(and also expected) by setting manual rows and columns
Any help would be appreciated. Thanks
Well there are two extensions, which would achieve just what you need:
even-parents
no-overlap
Coincidentally, both come from the same person, so this should not be a problem at all, all you have to do from there is to apply the right styles for the application to look like your example:
document.addEventListener("DOMContentLoaded", function() {
var cy = (window.cy = cytoscape({
container: document.getElementById("cy"),
layout: {
name: "evenParent"
},
style: [{
selector: "node",
style: {
"content": "data(id)",
"background-color": "#ad1a66"
}
},
{
selector: ":parent",
style: {
"background-opacity": 0.333
}
},
{
selector: "edge",
style: {
width: 3,
"line-color": "#ad1a66"
}
},
{
selector: "edge.meta",
style: {
width: 2,
"line-color": "red"
}
},
{
selector: ":selected",
style: {
"border-width": 3,
"border-color": "#DAA520"
}
}
],
elements: {
nodes: [{
data: {
id: "Jerry",
name: "Jerry"
}
},
{
data: {
id: "Elaine",
name: "Elaine"
}
},
{
data: {
id: "Kramer",
name: "Kramer"
}
},
{
data: {
id: "George",
name: "George"
}
},
{
data: {
id: "Martin",
name: "Martin"
}
},
{
data: {
id: "Philippe",
name: "Philippe"
}
},
{
data: {
id: "Louis",
name: "Louis"
}
},
{
data: {
id: "Genevieve",
name: "Genevieve"
}
},
{
data: {
id: "Leo",
name: "Leo"
}
},
{
data: {
id: "Larry",
name: "Larry"
}
},
{
data: {
id: "Logaina",
name: "Logaina"
}
}
],
edges: [{
data: {
source: "Jerry",
target: "Elaine"
}
},
{
data: {
source: "Jerry",
target: "Kramer"
}
},
{
data: {
source: "Jerry",
target: "George"
}
},
{
data: {
source: "Elaine",
target: "Martin"
}
},
{
data: {
source: "Elaine",
target: "Philippe"
}
},
{
data: {
source: "Elaine",
target: "Louis"
}
},
{
data: {
source: "Elaine",
target: "Genevieve"
}
},
{
data: {
source: "Elaine",
target: "Leo"
}
},
{
data: {
source: "Kramer",
target: "Larry"
}
},
{
data: {
source: "Kramer",
target: "Logaina"
}
}
]
}
}));
// demo your collection ext
cy.nodes().noOverlap({
padding: 5
});
});
body {
font: 14px helvetica neue, helvetica, arial, sans-serif;
}
#cy {
height: 100%;
width: 100%;
position: absolute;
left: 0;
top: 0;
}
<html>
<head>
<script src="https://unpkg.com/cytoscape/dist/cytoscape.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/cytoscape-even-parent#1.1.1/cytoscape-even-parent.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/cytoscape-no-overlap#1.0.1/cytoscape-no-overlap.min.js"></script>
</head>
<body>
<div id="cy"></div>
</body>
</html>
The following code worked for me,
Please consider #Stephen's code if this doesn't work.
var cy = cytoscape({
container: /* your div within which you want to render */ ,
elements: [ /*list of graph elements to start with */ ] ,
style: [ /* the stylesheet for the graph */ ] ,
layout:{
name: 'cola',
fit: false,
infinite: false,
avoidOverlap: true
}
});
//Used to make child nodes stay on the same row
cy.ready(function(){
setTimeout(function(){
cy.zoom(0.5);
cy.nodes(':compound').forEach(function(comp,j,comps){
var nodePosition={};
if(comp.descendants().length>1)
{
var minX;
var maxY;
comp.descendants().forEach(function(ele,i,eles){
if(i==0)
{
minX=ele.renderedPosition('x');
maxY=ele.renderedPosition('y');
}
else
{
var tempX=ele.renderedPosition('x');
var tempY=ele.renderedPosition('y');
if(tempX<minX)
{
minX=tempX;
}
if(tempY>maxY)
{
maxY=tempY;
}
}
});
comp.descendants().forEach(function(ele,i,eles){
ele.renderedPosition({x:minX,y:maxY});
minX=minX+60;
});
}
cy.resize();
cy.fit();
cy.minZoom(cy.zoom());
});
},1000);
});
P.S: Don't forget to include the cytoscape scripts;)

Cytsocape.js can't create edges in for loop

I'm creating chart with nodes and edges. Once I created nodes, I can't create the associated edges without getting those kind of errors :
Can not create edge 5134fb65-b30f-4947-9870-cc909e293e21 with nonexistant source Peter
My code :
var myJSONdata = info;
var cy = window.cy = cytoscape({
container: document.getElementById('cy'),
boxSelectionEnabled: false,
autounselectify: true,
style: [
{
selector: 'node',
style: {
'content': 'data(id)',
'text-opacity': 0.5,
'text-valign': 'center',
'text-halign': 'right',
'shape': 'hexagon',
'label': 'data(label)',
'background-color': '#11479e'
}
},
{
selector: 'edge',
style: {
'curve-style': 'bezier',
'width': 4,
'target-arrow-shape': 'triangle',
'line-color': '#9dbaea',
'target-arrow-color': '#9dbaea'
}
}
],
// elements: {
// nodes: [
// { data: { id: 'Peter' } },
// { data: { id: 'Claire' } },
// { data: { id: 'Mike' } },
// { data: { id: 'Rosa' } }
// ],
// edges: [
// { data: { source: 'Peter', target: 'Claire' } },
// { data: { source: 'Claire', target: 'Mike' } },
// { data: { source: 'Mike', target: 'Rosa' } }
// ]
// }
});
var array = [];
// Create nodes
for (var i = 0; i <= myJSONdata.length - 1; i++) {
array.push({
group: 'nodes',
data: {
id: i,
label: myJSONdata[i].name
}
}
);
}
// Create edges
for (var i = 0; i <= myJSONdata.length - 1; i++) {
var source = myJSONdata[i].name;
array.push({
group: 'edges',
data: {
source: source,
target: myJSONdata[i].next_op_name
}
});
}
cy.add(array);
cy.layout({
name: 'circle'
}).run();
The "Create nodes" part is working, but the "Create edges" is not.
I tried the solution here but it does not work.
Actually I want to read data from JSON file to create the chart.
I can do it with :
elements: {
nodes: [
{ data: { id: 'Peter' } },
{ data: { id: 'Claire' } },
{ data: { id: 'Mike' } },
{ data: { id: 'Rosa' } }
],
edges: [
{ data: { source: 'Peter', target: 'Claire' } },
{ data: { source: 'Claire', target: 'Mike' } },
{ data: { source: 'Mike', target: 'Rosa' } }
]
}
But I want to automate it according to the JSON file in input.
This is my JSON file :
info = [
{
"name": "Peter",
"next_op_name": "Claire",
}, {
"name": "Claire",
"next_op_name": "Mike",
}, {
"name": "Mike",
"next_op_name": "Rosa",
}, {
"name": "Rosa",
"next_op_name": "Peter",
}
];
I can't understand what is wrong.
The source and target fields in the edge are the IDs of nodes, not labels.
When you create the nodes, you need to set id to myJSONdata[i].name as well.

How to run Cytoscape.js?

I am new to Cytoscape.js and also didn't write JavaScript or HTML before.
I installed Cytoscape.js by using npm:
npm install cytoscape
I then created a HTML file from HTML-Kit as follows:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<script src="cytoscape.js"></script>
</head>
</html>
I placed this HTML file under cytoscape.js-2.7.14 folder where the file cytoscape.js resides.
I then opened my HTML file with Chrome. The window (and tab) is opened, but there is nothing there.
I then modified my HTML file as follows:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>Testing Cytoscape</title>
</head>
<body>
<script src="cytoscape.js"></script>
</body>
</html>
But there is still nothing in the window when I opened the HTML file.
Any ideas on how to run Cytoscape.js?
Thanks for advice!
Cytoscape.js is a library.
Library can't do anything by itself. You can't just run it and get a result. You need to write your code to initialize and use a library.
To use it properly, follow tutorials and guides on their website.
You can use it many ways, with a web client side only, or distributed architecture with web server.
Here is an exemple for a web client side only, where cytoscape libraries are not downloaded but referenced on the web.
You can also use it though a notebook, e.g. with Observable.
https://observablehq.com/#nfigay/test-adding-compound-with-cytoscape-js
<!DOCTYPE>
<html>
<head>
<title>Test Compound Graph Editor</title>
<meta charset="utf-8"/>
<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1, maximum-scale=1">
<script src="https://unpkg.com/cytoscape#3.21.0/dist/cytoscape.min.js"></script>
<script src="https://unpkg.com/layout-base#2.0.1/layout-base.js"></script>
<script src="https://unpkg.com/cose-base#2.1.0/cose-base.js"></script>
<script src="https://unpkg.com/cytoscape-fcose#2.1.0/cytoscape-fcose.js"></script>
<script src="https://unpkg.com/cytoscape-expand-collapse#4.1.0/cytoscape-expand-collapse.js"></script>
<script src="https://unpkg.com/pure-uuid#1.6.2/uuid.js"></script>
</head>
<body>
<div id="cy" style="width:100%;height:90%;background-color:white"></div>
<div class="menu-container">
<div style="text-align:center" class="panel">
<button id="compound">Add Compound Node</button>
<button id="collapseAll">Collapse all</button>
<button id="collapseRecursively">Collapse Recursively</button>
<button id="expandAll">Expand all</button>
<button id="expandRecursively">Expand Recursively</button>
</div>
</div>
</body>
<script>
var myData = [
{ data: { id: "o", "label": "Top node" } },
{ data: { id: "a", parent: "o", "label": "a" } },
{ data: { id: "b", parent: "o" } },
{ data: { id: "c", parent: "o" } },
{ data: { id: "d", parent: "o" } },
{ data: { id: "e", parent: "o" } },
{ data: { id: "f", parent: "o" } },
{ data: { id: "a1", parent: "a" } },
{ data: { id: "b1", parent: "b" } },
{ data: { id: "c1", parent: "c" } },
{ data: { id: "d1", parent: "d" } },
{ data: { id: "e1", parent: "e" } },
{ data: { id: "f1", parent: "f" } },
{ data: { id: "a2", parent: "a" } },
{ data: { id: "b2", parent: "b" } },
{ data: { id: "c2", parent: "c" } },
{ data: { id: "d2", parent: "d" } },
{ data: { id: "e2", parent: "e" } },
{ data: { id: "f2", parent: "f" } },
{ data: { id: "a3", parent: "a" } },
{ data: { id: "b3", parent: "b" } },
{ data: { id: "c3", parent: "c" } },
{ data: { id: "d3", parent: "d" } },
{ data: { id: "e3", parent: "e" } },
{ data: { id: "f3", parent: "f" } },
{ data: { id: "a4", parent: "a" } },
{ data: { id: "b4", parent: "b" } },
{ data: { id: "c4", parent: "c" } },
{ data: { id: "d4", parent: "d" } },
{ data: { id: "e4", parent: "e" } },
{ data: { id: "f4", parent: "f" } },
{ data: { id: "a5", parent: "a" } },
{ data: { id: "b5", parent: "b" } },
{ data: { id: "c5", parent: "c" } },
{ data: { id: "d5", parent: "d" } },
{ data: { id: "e5", parent: "e" } },
{ data: { id: "f5", parent: "f" } },
{ data: { id: "a6", parent: "a" } },
{ data: { id: "b6", parent: "b" } },
{ data: { id: "c6", parent: "c" } },
{ data: { id: "d6", parent: "d" } },
{ data: { id: "e6", parent: "e" } },
{ data: { id: "f6", parent: "f" } }
];
var cy = window.cy = cytoscape({
container: document.getElementById("cy"),
ready: function () {
this.layout({
name: "fcose",
randomize: true,
fit: true,
animate: true,
nodeDimensionsIncludeLabels: true,
condense: false
}).run(20, 0, 10);
var api = this.expandCollapse({
layoutBy: {
name: "fcose",
animate: true,
randomize: false,
fit: true,
nodeDimensionsIncludeLabels: true,
condense: false
},
fisheye: true,
animate: true,
undoable: false
});
api.expandAll({
layoutBy: {
name: "fcose",
animate: true,
randomize: false,
fit: true,
nodeDimensionsIncludeLabels: true,
condense: false
},
fisheye: true,
animate: true,
undoable: false,
nodeDimensionsIncludeLabels: true,
condense: false
});
},
elements: myData,
style: [
{
selector: "node",
style: {
"label": (ele) => ele.data("label"),
"color": "blue",
"shape": "diamond"
}
},
{
selector: "node.cy-expand-collapse-collapsed-node",
style: {
"shape": "rectangle",
"border-color":"black",
"border-width":3,
"color":"blue"
}
},
{
selector: ":selected",
style: {
"overlay-color": "green",
"overlay-opacity": 0.3,
'background-color': 'green',
'shape': 'rectangle',
}
},
{
selector: ":parent",
style: {
"background-color": "yellow",
"z-compound-depth": "auto",
shape: "rectangle"
}
},
{
selector: "edge",
style: {
"target-arrow-shape": "triangle",
"target-endpoint": "outside-to-node",
"target-arrow-color": "lightgreen",
"line-color": "green",
"target-distance-from-node": 0
}
}
],
layout: { name: "fcose" },
style: [
{
selector: "edge",
style: {
"curve-style": "bezier",
"target-arrow-shape": "triangle"
}
}
],
wheelSensitivity: 0.5
});
var api = cy.expandCollapse("get");
document.getElementById("collapseAll").addEventListener("click", function () {
api.collapseAll();
});
document.getElementById("expandAll").addEventListener("click", function () {
api.expandAll();
});
document
.getElementById("collapseRecursively")
.addEventListener("click", function () {
api.collapseRecursively(cy.$(":selected"));
});
document
.getElementById("expandRecursively")
.addEventListener("click", function () {
api.expandRecursively(cy.$(":selected"));
});
document.getElementById("compound").addEventListener("click", function () {
var selection = cy.nodes(":selected");
if (selection.length < 1) {
return;
}
var parent = selection[0].parent().id();
for (let i = 1; i < selection.length; i++) {
if (parent !== selection[i].parent().id()) {
return;
}
}
var myUUID = new UUID(4);
const parentNode = {
data: { id: `${myUUID}`, parent: parent, label: "label" }
};
cy.add(parentNode);
for (let i = 0; i < selection.length; i++) {
selection[i].move({ parent: `${myUUID}` });
}
api.expandAll();
});
</script>
</html>

Select just the child nodes of a parent node, and eliminate (temporarily) from the graph all other nodes in cytoscape.js

I just modified a sample from the cytoscape.js ("Animated BFS") and added some nodes:
$(function(){ // on dom ready
$('#cy').cytoscape({
style: cytoscape.stylesheet()
.selector('node')
.css({
'content': 'data(id)',
'background-color': 'data(myColor)'
})
.selector('edge')
.css({
'target-arrow-shape': 'triangle',
'width': 2,
'line-color': '#ddd',
'target-arrow-color': '#ddd'
}),
elements: {
nodes: [
{ data: { id: 'a', myColor: '#035530', addinf: 'sometext' } },
{ data: { id: 'b' } },
{ data: { id: 'c' } },
{ data: { id: 'd' } },
{ data: { id: 'e' } },
{ data: { id: 'ABC', myColor: '#CBB089' } },
{ data: { id: 'DEF', myColor: '#C0E234' } },
{ data: { id: 'GHI', myColor: '#C0E234' } },
{ data: { id: 'JKL', myColor: '#C0E234' } },
{ data: { id: 'MNO', myColor: '#C0E234' } },
{ data: { id: 'PQR', myColor: '#C0E234' } },
{ data: { id: 'STR', myColor: '#C0E234' } },
{ data: { id: 'ZXY', myColor: '#C0E234' } }
],
edges: [
{ data: { id: 'a"e', weight: 2, source: 'a', target: 'e' } },
{ data: { id: 'ab', weight: 3, source: 'a', target: 'b' } },
{ data: { id: 'be', weight: 4, source: 'b', target: 'e' } },
{ data: { id: 'bc', weight: 5, source: 'b', target: 'c' } },
{ data: { id: 'ce', weight: 6, source: 'c', target: 'e' } },
{ data: { id: 'cd', weight: 2, source: 'c', target: 'd' } },
{ data: { id: 'de', weight: 7, source: 'd', target: 'e' } },
{ data: { id: 'S', source:'a', target: 'ABC'}},
{ data: { id: '1', source:'a', target: 'DEF'}},
{ data: { id: '2', source:'b', target: 'GHI'}},
{ data: { id: '3', source:'e', target: 'JKL'}},
{ data: { id: '4', source:'c', target: 'MNO'}},
{ data: { id: '5', source:'d', target: 'PQR'}},
{ data: { id: '6', source:'a', target: 'STR'}},
{ data: { id: '7', source:'ABC', target: 'ZXY'}}
]
},
layout: {
name: 'breadthfirst',
directed: true,
fit: true,
maximalAdjustments: 10,
nodeRepulsion : 1000,
nodeOverlap : 10,
roots: '#a',
padding: 10
},
hideEdgesOnViewport: true,
ready: function(){
window.cy = this;
}
});
}); // on dom ready
And this is the resulting graph that I obtained (manually curated):
)
So I just want to select for example the node 'a' ( by clicking it or by user input and save it in a variable) and all of the childs should remain displayed, but all the others should temporarily dissapear. Remaining with a photo like this:
In Cytoscape.js how could I do that:
Select the node 'a' and get all the childs to remain displayed, while the others dissapear.
And if I would want the child + the grandchild of 'a' the commands will be different?
Also, my last question: in node 'a' I have some additional information about the node "addinf: 'sometext'", how could it be also be displayed when the node is clicked?
Thanks in advance!
1 and 2. I had never needed to manipulate children, but I think it's possible to do that by using the eles.depthFirstSearch() function; you can set depth as 1 to get direct children, or any amount as you want. Check this documentation.
3. Personally, I prefered to create a function named clickInNode(), where I could do some stuff when a node is selected. Then, to call it I use:
var nodeClicked = cy.on('tap', 'node', function(e) {
clickInNode(e.cyTarget);
});
If you have a textbox with ID nodedata and wants to fill it with the addinf data from node, then you can use:
$('#nodedata').val(node.data('addinf'));
inside your clickInNode() function.
Hope I've been helpful/clear enough.
If you use directed eles.bfs(), you can build an array of visited elements -- perhaps limiting list based on depth.

Categories

Resources