Using the edge weight for force directed layout (CoSE) in cytoscape.js - cytoscape.js

I am not sure how best to utilize the edge weight (e.g. strength of interaction between two interacting proteins) while generating a force directed layout using the CoSE plugin in cytoscape.js. Could someone provide any pointers. Should it be "idealEdgeLength" or "edgeElasticity"?
(EDIT) Following is a figure showing what I currently get (A) and what I am trying to achieve (B). Also below are the parameters I used for generating the layout.
Thanks,
Datta.
PS: Click to view a figure showing the current (labelled "A") and expected (labelled "B") layouts. Following are layout options for "A".
var options = {
name: 'cose',
// Called on `layoutready`
ready: function () { },
// Called on `layoutstop`
stop: function () { },
// Whether to animate while running the layout
animate: true,
// Number of iterations between consecutive screen positions update (0 -> only updated on the end)
refresh: 20,
// Whether to fit the network view after when done
fit: true,
// Padding on fit
padding: 30,
// Constrain layout bounds; { x1, y1, x2, y2 } or { x1, y1, w, h }
boundingBox: undefined,
componentSpacing: 100,
// Whether to randomize node positions on the beginning
randomize: true,
// Whether to use the JS console to print debug messages
debug: false,
// Node repulsion (non overlapping) multiplier
nodeRepulsion: 400000,
// Node repulsion (overlapping) multiplier
nodeOverlap: 10,
// Ideal edge (non nested) length
idealEdgeLength: 10,
// Divisor to compute edge forces
edgeElasticity: 100,
// Nesting factor (multiplier) to compute ideal edge length for nested edges
nestingFactor: 5,
// Gravity force (constant)
gravity: 80,
// Maximum number of iterations to perform
numIter: 10000,
// Initial temperature (maximum node displacement)
initialTemp: 100,
// Cooling factor (how the temperature is reduced between consecutive iterations
coolingFactor: 0.95,
// Lower temperature threshold (below this point the layout will end)
minTemp: 1.0
};

You can specify functions instead of static numbers for some key CoSE layout settings. The functions take edges (or nodes, in some cases), so you can tailor the layout based on edge properties.
So you could do something like this:
idealEdgeLength: function (edge) {
// Default is: 10
// Instead, base it on "weight"
return edge.data().weight * .5
},
edgeElasticity: function (edge) {
// Default is: 100
// Instead, base it on "weight"
return edge.data().weight * 4
},
You'll have to experiment with ranges that work with the layout engine and the range of weight you are expecting as input, but that approach should work AOK.

The ideal edge length specifies a default-like value, whereas the elasticity specifies one of the forces that determine the final length. In general for physics simulation layouts, you will need to experiment with different values and evaluate the results for your specific graphs.

Related

Focus/Zoom in on part of the graph or a specific set of nodes or a single node

I am currently using Cytoscape to create a large graph with 500 nodes. I am using Dagre for the hierarchical layout.
Currently the graph is small on the screen because of number of nodes which makes sense but
Is there a way to focus on a single node once the graph is created. Or can I zoom in on a part of graph?
I have tried using animate filter on dagre but it animates the whole graph and does not focus or zoom in on one node or one part of the graph.
this.cy
.layout({
name: "dagre",
padding: 30,
animate: true, // whether to transition the node positions
animateFilter: function( node, i ){
if ( node[0]._private.data.type === "student") {
return true;
}
},
transform: function( node, pos ){ return pos; },
})
.run();
Also tried zoom, But I only want to zoom one or set of nodes at the same time
cy.zoom({
level: 1.1, // the zoom level
//How can I filter the nodes I want?
});

How to do series/parallel animation in react-native-reanimated 2?

I'm looking for the equivalent of Animated.sequence and Animated.parallel from react-native. So far from the docs for v2, I could only see the withSequence function that changes the value of only on value and therefore the style of only one component in series.
What I was looking for was to trigger animations in two different components, either in series or in parallel.
For parallel, it seems changing values in statements one after another worked. Correct me if I'm wrong.
// these will run in parallel
val1Shared.value = withTiming(50);
val2Shared.value = withTiming(100);
But for series, I need to have each animation inside a useTiming callback. Which leads to kind of callback hell.
val1Shared.value = withTiming(50, undefined, () => {
val2Shared.value = withTiming(100);
});
Please help with the best practices in achieving this with reanimated 2.
Thanks.
I think there is no way of doing it like in Animated.
This library requires you to think a different way. If you want you run two animations (each one for a separate view) using interpolation, you can use a single shared value and a sufficient interpolation config.
Let's assume (according to your example) that you have two views you want to animate. The first animation is from 0 to 50, the second one is from 0 to 100.
Let's also assume you're transforming an X axis (I don't know what's your case, but it's going to be very similar) and we count the animation progress from 0 to 1, and both views will animate for the same period of time.
Initialize the shared value:
const animation = useSharedValue(0);
And do sth like this (of your choice):
animated.value = withTiming(1, { duration, easing });
For the first view, your transformation will look like this:
const animatedStyles1 = useAnimatedStyle(
() => ({
transform: [
{
translateX: interpolate(animation.value, [0, 0.5, 1], [0, 50, 50]),
},
],
}),
[mode, rectSize]);
and for the second one, like this:
const animatedStyles2 = useAnimatedStyle(
() => ({
transform: [
{
translateX: interpolate(animation.value, [0, 0.5, 1], [0, 0, 100]),
},
],
}),
[mode, rectSize]);
Now the explanation.
For the first view, we only work for the half of progress from the whole animation, so we from 0 to 0.5 we'll animate from 0 to 50. then, for the reset of the progress we'll stay in the same place (this is called a dead zone), to from 0.5 to 1 value of the progress does not change (50 to 50).
Now, for the second view, we wait for the progress to be in half, so from 0 to 0.5 we don't do anything (0 to 0). Then, when the progress is in half, we animate the view from 0 to 150.
In general, that way you can orchestrate the whole thing using just a single shared value.
Here you can find more info about the interpolation. The docs is from the react-native's Animated, but the idea is the same.
Good luck!

How do I make cose graph not snap into place?

I am creating a network graph using Cytoscape JS with the cose layout. The issue I am running into is that when i am animating my graph, it eases into its end position and then it snaps into a different position.
I have tried turning of the fit, defining boundingBox, increasing and decreasing the minTemp as well as increasing the coolingFactor.
The following is what layout variables are:
export default {
name: 'cose',
// Called on `layoutready`
ready: function(){},
// Called on `layoutstop`
stop: function(){},
// Whether to animate while running the layout
// true : Animate continuously as the layout is running
// false : Just show the end result
// 'end' : Animate with the end result, from the initial positions to the end positions
animate: 'end',
// Easing of the animation for animate:'end'
// Options: 'ease', 'linear'(default if undefined), ... potentially more options but need to find them
animationEasing: 'ease',
// The duration of the animation for animate:'end'
animationDuration: 3000,
// A function that determines whether the node should be animated
// All nodes animated by default on animate enabled
// Non-animated nodes are positioned immediately when the layout starts
animateFilter: function ( node, i ){ return true; },
// The layout animates only after this many milliseconds for animate:true
// (prevents flashing on fast runs)
animationThreshold: 1000,
// Number of iterations between consecutive screen positions update
refresh: 10,
// Whether to fit the network view after when done
fit: true,
// Padding on fit
padding: 20,
// Constrain layout bounds; { x1, y1, x2, y2 } or { x1, y1, w, h }
boundingBox: undefined,
// Excludes the label when calculating node bounding boxes for the layout algorithm
nodeDimensionsIncludeLabels: true,
// Randomize the initial positions of the nodes (true) or use existing positions (false)
randomize: true,
// Extra spacing between components in non-compound graphs
componentSpacing: 10,
// Node repulsion (non overlapping) multiplier
nodeRepulsion: function( node ){ return 1000000000; },
// Node repulsion (overlapping) multiplier
// NOTE: effects spacing of nodes
nodeOverlap: 100000000,
// Ideal edge (non nested) length
idealEdgeLength: function( edge ){ return 50; },
// Divisor to compute edge forces
edgeElasticity: function( edge ){ return 1; },
// Nesting factor (multiplier) to compute ideal edge length for nested edges
nestingFactor: 0.1,
// Gravity force (constant)
gravity: -1000,
// Maximum number of iterations to perform
numIter: 20000,
// Initial temperature (maximum node displacement)
initialTemp: 100,
// Cooling factor (how the temperature is reduced between consecutive iterations
coolingFactor: 0.999,
// Lower temperature threshold (below this point the layout will end)
minTemp: 10.0,
};
If you want a more sophisticated force-directed layout, you should use COSE Bilkent or fCOSE. The bundled COSE is fast and small in file size but it has less features.

Can Cytoscape.js with Dagre layout draw a vertical tree?

Is it possible to configure this to display a vertical tree instead of a horizontal tree? What I mean by vertical is something similar to Windows Explorer.
We have some users that would prefer to work with it that way.
The dagre layout extension has a github page with some useful default values for the layout:
var defaults = {
nodeSep: undefined, // the separation between adjacent nodes in the same rank
edgeSep: undefined, // the separation between adjacent edges in the same rank
rankSep: undefined, // the separation between adjacent nodes in the same rank
rankDir: undefined // 'TB' for top to bottom flow, 'LR' for left to right,
ranker: undefined, // Type of algorithm to assign a rank to each node in the input graph. Possible values: 'network-simplex', 'tight-tree' or 'longest-path'
minLen: function( edge ){ return 1; }, // number of ranks to keep between the source and target of the edge
edgeWeight: function( edge ){ return 1; }, // higher weight edges are generally made shorter and straighter than lower weight edges
// general layout options
fit: true, // whether to fit to viewport
padding: 30, // fit padding
spacingFactor: undefined, // Applies a multiplicative factor (>0) to expand or compress the overall area that the nodes take up
nodeDimensionsIncludeLabels: false, // whether labels should be included in determining the space used by a node
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
boundingBox: undefined, // constrain layout bounds; { x1, y1, x2, y2 } or { x1, y1, w, h }
transform: function( node, pos ){ return pos; }, // a function that applies a transform to the final node position
ready: function(){}, // on layoutready
stop: function(){} // on layoutstop
}
The important part here is the rankDir, you can define LR there :)

Only use slicebox cuboid option

Does anyone know how I can ensure only the cuboid animation is used on my slider? I don't particularly love the slicing action but do like the rotating cube options both left to right and top to bottom. I have checked the docs but can only see how to change orientation of the slicing animation or set to random.
The JS settings referred to in the docs are here:
JS
$.Slicebox.defaults = {
// (v)ertical, (h)orizontal or (r)andom
orientation : 'h',
// perspective value
perspective : 1200,
// number of slices / cuboids
// needs to be an odd number 15 => number > 0 (if you want the limit higher, change the _validate function).
cuboidsCount : 5,
// if true then the number of slices / cuboids is going to be random (cuboidsCount is overwitten)
cuboidsRandom : false,
// the range of possible number of cuboids if cuboidsRandom is true
// it is strongly recommended that you do not set a very large number :)
maxCuboidsCount : 5,
// each cuboid will move x pixels left / top (depending on orientation). The middle cuboid doesn't move. the middle cuboid's neighbors will move disperseFactor pixels
disperseFactor : 0,
// color of the hidden sides
colorHiddenSides : '#222',
// the animation will start from left to right. The left most cuboid will be the first one to rotate
// this is the interval between each rotation in ms
sequentialFactor : 150,
// animation speed
// this is the speed that takes "1" cuboid to rotate
speed : 600,
// transition easing
easing : 'ease',
// if true the slicebox will start the animation automatically
autoplay : true,
// time (ms) between each rotation, if autoplay is true
interval: 3000,
// the fallback will just fade out / fade in the items
// this is the time fr the fade effect
fallbackFadeSpeed : 300,
// callbacks
onBeforeChange : function( position ) { return false; },
onAfterChange : function( position ) { return false; },
onReady : function() { return false; }
};
I haven't copied all the js code as there's lots!
You just need to change number of slices to 1
cuboidsCount : 1