ivis-at-bilkent / cytoscape.js-cise Goto Github PK
View Code? Open in Web Editor NEWAn implementation of the circular layout algorithm by Dogrusoz et al. as a Cytoscape.js extension
License: MIT License
An implementation of the circular layout algorithm by Dogrusoz et al. as a Cytoscape.js extension
License: MIT License
Below graph with nodes allowed inside with a ratio of 0.3, we get overlaps:
symmetric_planar(16,30).graphml.txt
Similar to fcose, this extension should have an option for tiling (named tile
). When tiling is enabled, we should make sure it works nicely with options packComponents
and randomize
.
Now that layout-utilities supports incremental packing, let's make sure that's also properly used. We should mention the usage of packing (both incrementally and otherwise) in the README similar to fcose as well.
I suspect non-incremental packing of components are not working.
We are using the cytoscape.js and cytoscape-cise npm package on our project and have encountered a problem with Google authentication that this package causes. The following error appears in the console when the Google authentication popup appears, the popup is empty, and authentication is blocked:
Uncaught TypeError: Cannot read properties of undefined (reading 'label')
at Function.CiSEOnCircleNodePair.toString (cytoscape-cise.js:3155:1)
at RegExp.test ()
Step to reproduce:
Desired behavior:
Authentication through Google is working; the popup contains functionality for authorization, and there is no error in the console.
The code:
import React, {useEffect, useRef} from 'react';
export const GraphComponent = ({tags, edges, subjects}) => {
const cyRef = useRef();
const clusters = [];
const nodes = [];
tags &&
subjects.forEach((subject) => {
let clusterArray = tags
.filter((tag) => tag.subject.id === subject.id)
.map((tag) => tag.id);
if (clusterArray.length > 0) clusters.push(clusterArray);
});
tags.forEach((tag) =>
nodes.push({
data: {
id: tag.id,
label: tag.title || '',
counter: tag.countResults * 10,
subjectColor: tag?.subject.color,
subjectTitle: tag?.subject.title,
},
classes: 'theme',
})
);
const checkedNodes = nodes || [];
const checkedEdges = edges || [];
const ciseOptions = {
// -------- Mandatory parameters --------
name: 'cise',
clusters: clusters,
animate: 'end',
refresh: 10,
animationDuration: undefined,
animationEasing: undefined,
fit: true,
padding: 20,
nodeSeparation: 12,
idealInterClusterEdgeLengthCoefficient: 2.0,
allowNodesInsideCircle: false,
maxRatioOfNodesInsideCircle: 0.1,
springCoeff: 0.45,
nodeRepulsion: 4500,
gravity: 0.25,
gravityRange: 3.8
};
useEffect(() => {
const cytoscape = require('cytoscape');
const cise = require('cytoscape-cise');
cytoscape.use(cise); // register extension
let cy = cytoscape({
style: [
{
selector: 'node',
style: {
shape: 'circle',
'background-color': 'data(subjectColor)',
'border-color': '#0A0E16',
'border-width': '1',
label: 'data(label)',
height: 'data(counter)',
width: 'data(counter)',
},
},
{
selector: 'edge',
style: {
width: 1,
'background-color': '#FFFFFF99',
},
},
{
selector: 'label',
style: {
color: '#fff',
'font-size': 24,
margin: "12",
},
},
],
});
cy.mount(cyRef.current);
const graphElements = [...checkedNodes, ...checkedEdges];
cy.add(graphElements);
const layout = cy.layout(ciseOptions);
layout.run();
return () => {
cy.destroy();
};
}, []);
return <div ref={cyRef}></div>;
};
The code works fine apart from this authorization block. We tried to use authorization both in the popup and in a separate window - in both cases the same error appears in the console.
We also tried to connect the cytoscape and cytoscape-cise libraries via import - authorization blocking occurs in all cases.
Authorization is blocked on any page if the user has previously visited the page where the component with cytoscape was loaded. It seems that cytoscape-cise reacts to a new window created during authorization. Also, bug is reproduced even if we don't use the cise layout but import the cytoscape-cise library.
How to restrict the library cytoscape to the component in which it should run and prevent running during authentication?
I tried with the demo and a personal project. My browser is Opera. I also tried with Firefox but it doesn't work either. When I exported the json and looked at the nodes the positions show NaN.
This is pointed in #24, but I wanted to open it as a separate issue. If a function is given for clusters
option while packComponents
is enabled, it throws error, because component packing related code assumes clusters option as an array.
In the documentation it is written that you can specify clusters property in layout options with a function. But when I am doing the following clusters are not according to clusterid but according to connectivity.
My code:-
const layout = this.cy.layout({ name: 'cise',
clusters:function(node){return node.clusterID},
allowNodesInsideCircle:false,
maxRatioOfNodesInsideCircle:0.1,
animate:false,
refresh: 10,
idealInterClusterEdgeLengthCoefficient: 1.4});
layout.run();
Could you please let me know the change which I need to have this working.
I am trying to use your layout because it seems absolutely wonderful, but the different parameters related to the force-directed par of the layout seems to have 0 effects on the end result.
This is problematic because I have networks really divided, so I would like to increase gravity so that they are more "concentrated".
Did I do something wrong while using it, or are they simply not working?
I have been trying to externally import graph using graphml format file, but failed with various attempts. Just wondering could anyone help to provide a working example of the input graphml format file, for example, the graph given in the demo.
Thanks!
The layout initialised with cise layout
The layout executed after the network was initialised with a fcose layout.
As you can see, when I initialise directly with the cise layout, the global space is much better used, all the disconnected subgraphs being arranged within a "compacted" square, which allows a better overview with a simple glance.
On the other hand, when I run the layout on the same graph initialised with a fcose layout, the result is totally different, with disconnected subgraphs arranged on a diagonal, and so filling a lot more space, thus having globally smaller nodes and reducing the visibility of the drawn data.
Any idea on why such different behaviour? (The used parameters are exactly the same)
Since layout-base now supports function input for nodeRepulsion, edgeElasticity and idealEdgeLength options, CiSE should be updated to support this functionality. Currently, I made some changes on nodeRepulsion and edgeElasticity(springCoeff) options to get the layout working again, but it is not complete. Changes required for this functionality should be evaluated comprehensively because of the complex structure of the layout. In addition to that, layout currently doesn't have idealEdgeLength option which can be exposed during these changes.
Using a new option name "randomize" we should implement an incremental version of this layout style (similar to other Cytoscape.js layout extensions).
Currently, we seem to check whether or not we should enlarge a cluster in every iteration. This is not very reliable since the situation might change over iterations similar to other heuristics like swapping neighboring nodes on a circle. So we should accumulate such data over a number of iterations and enlarge it if needed.
We should also make sure that this check is not done redundantly as it's done currently for every in-circle node but only once per cluster! I think we should move all the nodes first and then do this enlarge check with a certain frequency.
According to @canbax When there are no clusters or just a small one, the performance is laggy.
See https://github.com/ugurdogrusoz/visuall/issues/308.
When CiSE runs, it might shift the center of the drawing arbitrarily (see this for an example). In order to avoid this, we should calculate the center of the drawing before layout and move the laid-out drawing back to this location. This should be the case for each individual component if packing is enabled.
When inner nodes are allowed with a high ratio, we get situations like the following.
This might be due to two reasons:
So I am getting this console message:
Uncaught TypeError: Cannot read property 'layoutBase' of undefined
at Object.<anonymous> (cytoscape-cise.js:1209)
at __webpack_require__ (cytoscape-cise.js:30)
at Object.<anonymous> (cytoscape-cise.js:3284)
at __webpack_require__ (cytoscape-cise.js:30)
at Object.<anonymous> (cytoscape-cise.js:205)
at __webpack_require__ (cytoscape-cise.js:30)
at Object.<anonymous> (cytoscape-cise.js:3242)
at __webpack_require__ (cytoscape-cise.js:30)
at cytoscape-cise.js:76
at cytoscape-cise.js:79
I haven't used the cise in the code I provided because it didnt work at all. So I just implemented a small concentric layout example.
This is my code:
<html>
<head>
<style>
#cy {
width: 100%;
height: 100%;
position: absolute;
top: 0px;
left: 0px;
}
</style>
<script src="https://cdnjs.cloudflare.com/ajax/libs/cytoscape/3.19.0/cytoscape.min.js"></script>
<script src="https://unpkg.com/layout-base/layout-base.js"></script>
<script src="./cytoscape-cise.js"></script>
</head>
<body>
<div id="cy"></div>
<script>
var head = 'a';
var cy = cytoscape({
container: document.getElementById('cy'), // container to render in
elements: [ // list of graph elements to start with
{ // node a
data: { id: head }
}
],
style: [ // the stylesheet for the graph
{
selector: 'node',
style: {
'background-color': '#667',
'label': 'data(id)'
}
},
{
selector: 'edge',
style: {
'width': 1,
'line-color': '#ccc',
'target-arrow-color': '#ccc',
'target-arrow-shape': 'triangle',
'curve-style': 'bezier'
}
}
],
});
for(var i=0; i < 10; ++i) {
cy.add([
{
data: {id: i} ,
},
{
data: {
id: head + i,
source: head,
target: i
}
}
]);
}
cy.layout({
name: 'concentric',
}).run();
</script>
</body>
</html>
Can you please help me with this? :)
When a graph is disconnected and packing of components is enabled and a cluster spans multiple components, we should merge the multiple components spanning the same cluster and process accordingly. In other words, the fact that two nodes are in the same cluster should force the components that these nodes are in to be combined.
Are there types, I couldn't find any.
In "Layout Options" of demo, number input fields can be refined in the following ways:
When allowNodesInsideCircle
is true, maxRatioOfNodesInsideCircle
determines how many nodes are allowed inside each cluster / circle but this option doesn't seem to work properly. In below example we use the default value of this option, which is 0.1. That means we should allow at most 10 percent of the nodes in the circle, which is less than one. Yet we try to put a node inside the circle for clusters with only 6 nodes and they won't fit.
I'm using the below layout options.
{
"name": "cise",
"clusters": [
[
"n2",
"n1045152",
"n1076797",
"n1045573",
"n1045238"
]
],
"randomize": false,
"animate": "end",
"refresh": 10,
"animationDuration": 500,
"fit": true,
"padding": 30,
"nodeSeparation": 10,
"idealInterClusterEdgeLengthCoefficient": 1.4,
"allowNodesInsideCircle": true,
"maxRatioOfNodesInsideCircle": 0.1,
"springCoeff": 0.45,
"nodeRepulsion": 4500,
"gravity": 0.25,
"gravityRange": 3.8,
"packComponents": true
}
with the graph attached as a JSON file
small-graph.txt
I get the error below.
core.js:6210 ERROR TypeError: Cannot read property 'getInnerNodePushCount' of undefined
at CiSELayout.clusterEnlargementCheck (cytoscape-cise.js:2053)
at CiSELayout.runSpringEmbedderTick (cytoscape-cise.js:2031)
at Layout.tick (cytoscape-cise.js:3735)
at tick (cytoscape-cise.js:4396)
at multitick (cytoscape-cise.js:4420)
at Layout.run4state (cytoscape-cise.js:4211)
at Layout.run (cytoscape-cise.js:4229)
Please also note that I'm calling eles.layout on all the existing elements.
One particular improvement here might be using the cosep algorithm (instead of cose) for laying out the quotient graph. Here we need to carefully position circle nodes and set the port constraints accordingly though. Let's discuss.
This problem is caused by the grid implementation. Before the commit 1490906, the root graph's bound was not updated recursively for both in-circle enabled and disabled options as both caused errors when for example there are one enormous node and relatively tiny nodes but now it is updated recursively for the case there is no in circle nodes. The reason recursive update is not done when there are in circle nodes is that it messes up the whole layout. updateBounds() function is in LGraph class of layout-base:
https://github.com/iVis-at-Bilkent/layout-base/blob/3f7549940feef31416cc35ef8256282ebc4d1ecd/src/LGraph.js#L248
I observed that if a graph has a high degree on-circle node (green-bordered) as in the below image, than graph drifts excessively (more than 10000 pixels) both in randomized and incremental layout. However, in randomized case it drifts one time and then stays around that position, while in incremental case it continues drifting.
To reproduce:
CiSE should have an option (see nodeDimensionsIncludeLabels
in fcose layout for instance) that takes node labels into account when calculating node dimensions.
From @MaxFranz:
It would be nice to have a demo where the clusters are not predefined. Maybe this new demo could use one of the built-in clustering algorithms in the core lib. I suspect this would be a common use-case, and having the demo would avoid people asking questions in the issue tracker. A simpler alternative to the new demo would be a "How to specify clusters" section in the readme, with a code example. Again, I don't think this is something that we need right away.
Sometimes, cluster circles are laid out too wide when allowNodesInsideCircle
option is enabled. A sample case to reproduce:
Let's use this extension to pack the components of disconnected graphs, just like we do with this layout - see its demo and Pack Components to Window option in the demo.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.