Cytoscape.js setting node colour and other details - cytoscape.js

I am using Cytoscape.js to create a basic diagram and am curious as to how to set the colour and particular shape of each node. Here is my existing code:
layout: {
name: 'preset'
},
ready: function(){
window.cy = this;
cy.add([
{ group: "nodes", data: { id: "n0" }, position: { x: 100, y: 100 } },
{ group: "nodes", data: { id: "n1", shape: 'rectangle' }, position: { x: 200, y: 200 } },
{ group: "edges", data: { id: "e0", source: "n0", target: "n1" } }
]);
}
});
});
I was also curious as to how to animate the diagram and if there were any similar examples out there on that.
cheers,

...
style: [ // the stylesheet for the graph
{
selector: 'node',
style: {
'background-color': '#666',
'shape': 'rectangle',
}
},
],
...
background-color is probably the attribute you are looking for, this is set in the style option. More info can be in http://js.cytoscape.org/#getting-started/specifying-basic-options.
As for the shape, cytoscape has a few predefined shapes such as rectangle, circle, etc. You can even make your own, or have an svg as the node's image. Options for nodes are listed in http://js.cytoscape.org/#style/node-body.
For animation I would look at some of the demos uploaded and go from there. This one is particularly interesting js.cytoscape.org/demos/aedff159b0df05ccfaa5

Related

Hide Pie Chart Slice on Load

I would like to hide a pie chart slice on load but cannot figure out how to do so.
I'm not sure it's possible, but it seems like it might be. There is a property "selected", but it does not seem to change when I manually select or unselect a wedge via the legend. I've tried to dispatchAction like this example (example), but haven't had any luck:
I think you are close to the solution... Actually, you should tweak legend.selected.
Take a look at this basic example:
let option = {
legend: {
selected: {
'B': false // <--- HERE
}
},
series: [
{
type: 'pie',
label: {
position: 'inner'
},
data: [
{ value: 10, name: 'A' },
{ value: 20, name: 'B' },
{ value: 15, name: 'C' }
]
}
]
};
let myChart = echarts.init(document.getElementById('main'));
myChart.setOption(option);
#main {
width: 300px;
height: 300px;
}
<script src="https://cdn.jsdelivr.net/npm/echarts#5.4.1/dist/echarts.min.js"></script>
<div id="main"></div>

Keep edges seperated

I have created the following diagram using ELK.
Now I'm trying to use cytoscape.js with cytoscape.js-elk to generate the same routing. However I cannot get the edges the same was with ELK.
I keep getting the following:
What do I need to do to get the same edge route as ELK generates? I have tried changing the ELK options, but I don't think this is caused by elk, I think this is caused by cytoscape.
My style
const style = [ // the stylesheet for the graph
{
selector: 'node',
style: {
shape: 'rectangle',
label: 'data(id)',
'font-size': '0.5em',
}
},
{
selector: 'edge',
style: {
'width': 1,
'curve-style': 'taxi',
'line-color': '#ccc',
label: 'data(id)',
'font-size': '0.5em',
'color': 'blue',
'target-arrow-color': '#ccc',
'target-arrow-shape': 'triangle'
}
}
];
Settings
cytoscape.use(elk);
var cy = cytoscape({
container: document.getElementById('cy'),
style: style,
layout: { name: 'elk' }
});
Nodes & Edges
var nodes = cy.add([
{ group: 'nodes', data: { id: 'n1'} },
{ group: 'nodes', data: { id: 'n2'} },
{ group: 'nodes', data: { id: 'n4'} },
{ group: 'nodes', data: { id: 'n9'} },
{ group: 'nodes', data: { id: 'n10' } },
{ group: 'nodes', data: { id: 'n555'} },
{ group: 'nodes', data: { id: 'n556'} },
{ group: 'nodes', data: { id: 'n557'} },
])
var edges = cy.add([
{ group: 'edges', data: { id: 'e3', source: 'n1', target: 'n4' } },
{ group: 'edges', data: { id: 'e19', source: 'n1', target: 'n9' } },
{ group: 'edges', data: { id: 'e12', source: 'n2', target: 'n1' } },
{ group: 'edges', data: { id: 'e842', source: 'n2', target: 'n9' } },
{ group: 'edges', data: { id: 'e15', source: 'n2', target: 'n10' } },
{ group: 'edges', data: { id: 'e10', source: 'n4', target: 'n2' } },
{ group: 'edges', data: { id: 'e908', source: 'n4', target: 'n4' } },
{ group: 'edges', data: { id: 'e843', source: 'n4', target: 'n9' } },
{ group: 'edges', data: { id: 'e11', source: 'n4', target: 'n10' } },
{ group: 'edges', data: { id: 'e905', source: 'n4', target: 'n555' } },
{ group: 'edges', data: { id: 'e862', source: 'n4', target: 'n557' } },
{ group: 'edges', data: { id: 'e802', source: 'n9', target: 'n1' } },
{ group: 'edges', data: { id: 'e7', source: 'n10', target: 'n2' } },
{ group: 'edges', data: { id: 'e8', source: 'n10', target: 'n4' } },
]);
Options
var options = {
name: "elk",
nodeDimensionsIncludeLabels: true, // Boolean which changes whether label dimensions are included when calculating node dimensions
fit: true, // Whether to fit
padding: 20, // Padding on fit
animate: false, // Whether to transition the node positions
animateFilter: function (node, i) { return true; }, // Whether to animate specific nodes when animation is on; non-animated nodes immediately go to their final positions
animationDuration: 500, // Duration of animation in ms if enabled
animationEasing: undefined, // Easing of animation if enabled
transform: function (node, pos) { return pos; }, // A function that applies a transform to the final node position
ready: undefined, // Callback on layoutready
stop: undefined, // Callback on layoutstop
elk: {
'algorithm': 'layered',
'layered.mergeEdges': 'false',
'layered.mergeHierarchyEdges': 'false',
'crossingMinimization.semiInteractive': true,
'nodePlacement.strategy': 'NETWORK_SIMPLEX',
'layered.wrapping.additionalEdgeSpacing': 50,
'spacing.nodeNode': 50,
'spacing.nodeNodeBetweenLayers': 25,
'spacing.edgeNode': 25,
'spacing.edgeNodeBetweenLayers': 20,
'spacing.edgeEdge': 20,
'spacing.edgeEdgeBetweenLayers': 15,
// All options are available at http://www.eclipse.org/elk/reference.html
// 'org.eclipse.elk.' can be dropped from the Identifier
// Or look at demo-demo.js for an example.
// Enums use the name of the enum e.g.
// 'searchOrder': 'DFS'
//
// The main field to set is `algorithm`, which controls which particular
// layout algorithm is used.
},
priority: function (edge) { return null; }, // Edges with a non-nil value are skipped when geedy edge cycle breaking is enabled
};
cy.layout(options).run();
I hit the same problem. Another you will encounter is that the lines will go through the nodes, there is no effort to route around them. For me this has rendered taxi useless, even though I much prefer it's appearance. I am not aware of any line drawing algorithm in cytoscape that fixes either of these issues.
My reluctant conclusion is that I need to switch platforms, and transfer entirely to Sprotty and ELK (which was probably used to draw your reference graph).
https://rtsys.informatik.uni-kiel.de/elklive/examples.html?e=general%2FmixingDirection
https://www.typefox.io/blog/sprotty-a-web-based-diagramming-framework
Examples with Sprotty show lines actually routing around nodes, and junction points on nodes to show where overlapping lines actually join. Additionally it uses SVGs rather than a raster-render system. This may result in a crisper font, but also has the advantage of searchable text in your diagram (if you care about that).
I have yet to take the plunge on yet another framework, but it looks good.
I am also facing similar kind of problem where my edges are overlapping to each other. To overcome this problem you can use curve-style: straight;.
Edges type demo

cytoscape.js: How to prevent adjacent taxi edges from overlapping

I'm attempting to use a Dagre layout and taxi edges in cytoscape.js to show how nodes connect to other nodes. However, in some cases, due to how the corners of the edges can overlap, it appears that a node has multiple parents, where it actually has only one.
I've tried changing some of the taxi style settings for the edges, but since those are applied to all edges, I still experience the same issue (just in a different spot). Is there a configuration setting I'm missing that will prevent these unrelated edges from overlapping? Barring that, is there a way to change, say, the taxi-turn setting for only some edges? (To make it more complex, this will need to work with arbitrary nodes/edges provided by a user, so I'm unable to handle specific, one-off issues.)
I've reproduced the issue here: https://stackblitz.com/edit/react-rj7ln4?file=index.js
Specifically, the edges in question are from the last two nodes in the first column.
Styles, including configuration for taxi settings
const styles = [
// disable the visible selector when clicking to pan
{
selector: "core",
style: {
"active-bg-opacity": 0
}
},
// basic styling for nodes
{
selector: "node",
style: {
"background-clip": "none",
shape: "rectangle",
"background-opacity": 0,
"font-family": "serif"
}
},
// disable overlay when clicking on nodes or edges
{
selector: "node, edge",
style: {
"overlay-opacity": 0.1
}
},
// basic styles for edges
{
selector: "edge, edge:selected",
style: {
"line-color": "rgb(143,156,173)",
"curve-style": "taxi",
"edge-distances": "node-position",
"taxi-direction": "horizontal",
"taxi-turn": "75%",
"taxi-turn-min-distance": "30px",
"target-endpoint": "outside-to-node",
"target-arrow-shape": "triangle",
"target-arrow-color": "rgb(143,156,173)",
"target-distance-from-node": 15
}
},
// hide the boundary around compound nodes
{
selector: "node:parent",
style: {
opacity: 0.91
}
}
];
Array of nodes and edges used to reproduce
const elements = [
{
data: {
id: "A",
title: "A"
}
},
{
data: {
id: "B",
title: "B"
}
},
{
data: {
id: "C",
title: "C"
}
},
{
data: {
id: "D",
title: "D"
}
},
{
data: {
id: "E",
title: "E"
}
},
{
data: {
id: "F",
title: "F"
}
},
{
data: {
id: "AD",
source: "A",
target: "D"
}
},
{
data: {
id: "BD",
source: "B",
target: "D"
}
},
{
data: {
id: "CE",
source: "C",
target: "E"
}
},
{
data: {
id: "DF",
source: "D",
target: "F"
}
},
{
data: {
id: "EF",
source: "E",
target: "F"
}
}
];
Cytoscape.js version: 3.10.0
Browsers & versions: Firefox 70.0.1 / Chrome 78.0.3904.97 on macOS 10.14.6

Edge Data Format

I am trying to find the most efficient way to return data for a network graph which will be constructed with cytoscape js on the front end. I know that the standard way to add edges and nodes is :
// can use reference to eles later
var eles = cy.add([
{ group: 'nodes', data: { id: 'n0' }, position: { x: 100, y: 100 } },
{ group: 'nodes', data: { id: 'n1' }, position: { x: 200, y: 200 } },
{ group: 'nodes', data: { id: 'n2' }, position: { x: 300, y: 300 } },
{ group: 'edges', data: { id: 'e0', source: 'n0', target: 'n1' } },
{ group: 'edges', data: { id: 'e0', source: 'n0', target: 'n2' } }
]);
Taken from their documentation
I was wondering if there is a way to effectively do the following:
// can use reference to eles later
var eles = cy.add([
{ group: 'nodes', data: { id: 'n0' }, position: { x: 100, y: 100 } },
{ group: 'nodes', data: { id: 'n1' }, position: { x: 200, y: 200 } },
{ group: 'nodes', data: { id: 'n2' }, position: { x: 300, y: 300 } },
{ group: 'edges', data: { id: 'e0', source: 'n0', target: ['n1', 'n2'] } }
]);
This way I can return an adjacency list from the server instead of an edge/node list.
Intresting format, but unfortunately, this won't work without maybe a new extension.
The thing is, that every element of the graph has to have an id! So when you add an edge to the graph and assign multiple targets, there ought to be 2 id's for every edge.
If you are trying to optimise your cy instance, you can go over this section of the documentation instead.

How to set edges using JSON in cytoscape.js

I am using cytoscape.js for one of my usecases. Here, I prefer to display the graph with only nodes in the beginning as shown below.
var cy1 = cytoscape({
container: document.getElementById('cy'),
elements: {
nodes: countriesJSON
},
style: [
{
selector: 'node',
style: {
'background-color': '#666',
'label': 'data(id)'
}
},
{
selector: 'edge',
style: {
'width': 1,
'line-color': '#aaa',
}
}
]
});
cy1.layout({
name: 'circle'
});
Now, inside a function, I will form the edges as like this
function myfunc(){
...
...
allRoutes.map(function(d){
var inner={};
var obj = {}
inner["id"]="edge"+index
inner["source"]=data[0]
inner["target"]=data[1]
obj["data"]=inner
allLegsJSON[i]=obj;
i++;
})
...
...
cy1.elements({ edges: allLegsJSON });
}
Once edges are created, I want to assign edges to the graph as above. However, this code is not working. Can someone tell me how to do this? I wish to assign the edges and then update the cy1 graph.
This did this
cy1.add({ edges: allLegsJSON });