Merge pull request #3817 from bgruening/cytoscape

Cytoscape as the Galaxy charts plugin
This commit is contained in:
Aysam Guerler
2017-03-28 00:29:24 -04:00
committed by GitHub
17 changed files with 2366 additions and 109 deletions
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1 +1 @@
define( [], function() { return {nvd3_bar:require( "visualizations/nvd3/bar/config" ), nvd3_bar_horizontal:require( "visualizations/nvd3/bar_horizontal/config" ), nvd3_bar_horizontal_stacked:require( "visualizations/nvd3/bar_horizontal_stacked/config" ), nvd3_bar_stacked:require( "visualizations/nvd3/bar_stacked/config" ), nvd3_line:require( "visualizations/nvd3/line/config" ), nvd3_line_focus:require( "visualizations/nvd3/line_focus/config" ), nvd3_scatter:require( "visualizations/nvd3/scatter/config" ), nvd3_stackedarea:require( "visualizations/nvd3/stackedarea/config" ), nvd3_stackedarea_full:require( "visualizations/nvd3/stackedarea_full/config" ), nvd3_stackedarea_stream:require( "visualizations/nvd3/stackedarea_stream/config" ), nvd3_pie:require( "visualizations/nvd3/pie/config" ), nvd3_histogram:require( "visualizations/nvd3/histogram/config" ), nvd3_histogram_discrete:require( "visualizations/nvd3/histogram_discrete/config" ), jqplot_bar:require( "visualizations/jqplot/bar/config" ), jqplot_boxplot:require( "visualizations/jqplot/boxplot/config" ), jqplot_histogram_discrete:require( "visualizations/jqplot/histogram_discrete/config" ), jqplot_line:require( "visualizations/jqplot/line/config" ), jqplot_scatter:require( "visualizations/jqplot/scatter/config" ), biojs_msa:require( "visualizations/biojs/msa/config" ), biojs_drawrnajs:require( "visualizations/biojs/drawrnajs/config" ), others_example:require( "visualizations/others/example/config" ), others_heatmap:require( "visualizations/others/heatmap/config" ), others_heatmap_cluster:require( "visualizations/others/heatmap_cluster/config" ), cytoscape_basic:require( "visualizations/cytoscape/basic/config" ), pv_viewer:require( "visualizations/pv/viewer/config" ), benfred_venn:require( "visualizations/benfred/venn/config" ), ngl_viewer:require( "visualizations/ngl/viewer/config" ),} } );
define( [], function() { return {nvd3_bar:require( "visualizations/nvd3/bar/config" ), nvd3_bar_horizontal:require( "visualizations/nvd3/bar_horizontal/config" ), nvd3_bar_horizontal_stacked:require( "visualizations/nvd3/bar_horizontal_stacked/config" ), nvd3_bar_stacked:require( "visualizations/nvd3/bar_stacked/config" ), nvd3_line:require( "visualizations/nvd3/line/config" ), nvd3_line_focus:require( "visualizations/nvd3/line_focus/config" ), nvd3_scatter:require( "visualizations/nvd3/scatter/config" ), nvd3_stackedarea:require( "visualizations/nvd3/stackedarea/config" ), nvd3_stackedarea_full:require( "visualizations/nvd3/stackedarea_full/config" ), nvd3_stackedarea_stream:require( "visualizations/nvd3/stackedarea_stream/config" ), nvd3_pie:require( "visualizations/nvd3/pie/config" ), nvd3_histogram:require( "visualizations/nvd3/histogram/config" ), nvd3_histogram_discrete:require( "visualizations/nvd3/histogram_discrete/config" ), jqplot_bar:require( "visualizations/jqplot/bar/config" ), jqplot_boxplot:require( "visualizations/jqplot/boxplot/config" ), jqplot_histogram_discrete:require( "visualizations/jqplot/histogram_discrete/config" ), jqplot_line:require( "visualizations/jqplot/line/config" ), jqplot_scatter:require( "visualizations/jqplot/scatter/config" ), biojs_msa:require( "visualizations/biojs/msa/config" ), biojs_drawrnajs:require( "visualizations/biojs/drawrnajs/config" ), others_example:require( "visualizations/others/example/config" ), others_heatmap:require( "visualizations/others/heatmap/config" ), others_heatmap_cluster:require( "visualizations/others/heatmap_cluster/config" ), cytoscape_viewer:require( "visualizations/cytoscape/viewer/config" ), pv_viewer:require( "visualizations/pv/viewer/config" ), benfred_venn:require( "visualizations/benfred/venn/config" ), ngl_viewer:require( "visualizations/ngl/viewer/config" ),} } );
@@ -3,7 +3,7 @@
"jqplot" : [ "bar", "boxplot", "histogram_discrete", "line", "scatter" ],
"biojs" : [ "msa", "drawrnajs" ],
"others" : [ "example", "heatmap", "heatmap_cluster" ],
"cytoscape" : [ "basic" ],
"cytoscape" : [ "viewer" ],
"pv" : [ "viewer" ],
"benfred" : [ "venn" ],
"ngl" : [ "viewer" ]
@@ -0,0 +1,87 @@
/** Convert SIF files to JSON in a format required by Cytoscape
for rendering the graph */
/** Inspired from https://www.npmjs.com/package/sif.js */
define( [], function() {
function SIFJS() {};
// Private variables and methods
var nodes = {}, links = {}, content = [];
// Add a node
var _getNode = function( id ) {
if(!nodes[id]) {
nodes[id] = {id: id};
}
return nodes[id];
};
// Parse each line of the SIF file
var _parse = function( line, i ) {
var source = _getNode( line[0] ), interaction = ( line[1] ? line[1] : "" ), j, length;
line = ( line.split('\t').length > 1 ) ? line.split('\t') : line.split(' ');
if( line.length && line.length > 0 && line[0] !== "" ) {
if( interaction !== "" ) {
// Get all the target nodes for a source
for ( j = 2, length = line.length; j < length; j++ ) {
if( line[j] !== "" ) {
// Create an object for each target for the source
var target = _getNode( line[j] ),
relation_object = {target: target.id,
source: source.id,
id: source.id + target.id,
relation: interaction.replace(/[''""]+/g, '') }; // Replace quotes in relation
if( source < target ) {
links[ source.id + target.id + interaction ] = relation_object;
} else {
links[ target.id + source.id + interaction ] = relation_object;
}
}
}
}
// Handle the case of single node i.e. no relation with any other node
// and only the source exists
else {
links[ source.id ] = { target: "", source: source.id, id: source.id, relation: "" };
}
}
};
// Convert to array from objects
var _toArr = function( obj ) {
var arr = [];
for (var key in obj) {
arr.push( obj[key] );
}
return arr;
};
// Make content from list of nodes and links
var _toDataArr = function( nodes, links ) {
var content = [], node_length, links_length;
// Make a list of all nodes
for(var i = 0, node_length = nodes.length; i < node_length; i++) {
content.push( { 'data': nodes[i] } );
}
// Make a list of all relationships among nodes
for(var i = 0, links_length = links.length; i < links_length; i++) {
content.push( { 'data': links[i] } );
}
return content;
};
// Public method. Return graph data as JSON
SIFJS.parse = function( text ) {
var lines = text.split('\n'), i, length, nodesarr, linksarr;
for ( i = 0, length = lines.length; i < length; i++ ) {
_parse( lines[i], i );
}
nodesarr = _toArr( nodes );
linksarr = _toArr( links );
return { content: _toDataArr( nodesarr, linksarr ) };
};
return {
SIFJS : SIFJS
};
});
@@ -120,4 +120,4 @@ define( [], function() {
clone : clone,
isJSON : isJSON
};
});
});
@@ -1,9 +0,0 @@
define( [], function() {
return {
title : 'Cytoscape (Default)',
library : 'Cytoscape',
datatypes : [ 'json' ],
keywords : 'cytoscape graph nodes edges',
description : 'Basic Cytoscape viewer for connected graphs hosted at http://js.cytoscape.org.'
}
});
Binary file not shown.

Before

Width:  |  Height:  |  Size: 88 KiB

@@ -1,56 +0,0 @@
define( [ 'utilities/utils', 'plugins/cytoscape/cytoscape' ], function( Utils, Cytoscape ) {
return Backbone.Model.extend({
initialize: function( options ) {
var chart = options.chart;
var dataset = options.dataset;
Utils.get( {
url : dataset.download_url,
success : function( content ) {
try {
Cytoscape( Utils.merge( content, {
container: $( '#' + options.targets[ 0 ] ),
layout: {
name: 'cose',
idealEdgeLength: 100,
nodeOverlap: 20
},
style: Cytoscape.stylesheet()
.selector('node')
.css({
'content': 'data(name)',
'text-valign': 'center',
'color': 'white',
'text-outline-width': 2,
'text-outline-color': '#888'
})
.selector('edge')
.css({
'target-arrow-shape': 'triangle'
})
.selector(':selected')
.css({
'background-color': 'black',
'line-color': 'black',
'target-arrow-color': 'black',
'source-arrow-color': 'black'
})
.selector('.faded')
.css({
'opacity': 0.25,
'text-opacity': 0
})
} ) );
chart.state( 'ok', 'Chart drawn.' );
} catch( err ) {
chart.state( 'failed', err );
}
options.process.resolve();
},
error: function() {
chart.state( 'failed', 'Failed to access dataset.' );
options.process.resolve();
}
});
}
});
});
@@ -0,0 +1,87 @@
define( [], function() {
return {
title : 'Cytoscape',
library : 'Cytoscape',
datatypes : [ 'sif', 'json' ],
keywords : 'cytoscape graph nodes edges',
description : 'A viewer based on graph theory/ network library for analysis and visualisation hosted at http://js.cytoscape.org.',
settings : {
curve_style : {
label : 'Curve style',
help : 'Select a curving method used to separate two or more edges between two nodes.',
type : 'select',
display : 'radio',
value : 'haystack',
data : [ { label : 'Haystack', value : 'haystack' },
{ label : 'Bezier', value : 'bezier' },
{ label : 'Unbundled bezier', value : 'unbundled-bezier' },
{ label : 'Segments', value: 'segments' } ]
},
layout_name : {
label : 'Layout name',
help : 'Select a kind of position of nodes in graph.',
type : 'select',
display : 'radio',
value : 'haystack',
data : [ { label : 'Breadth First', value : 'breadthfirst' },
{ label : 'Circle', value : 'circle' },
{ label : 'Concentric', value : 'concentric' },
{ label : 'Cose', value : 'cose' },
{ label : 'Grid', value : 'grid' },
{ label : 'Null', value: 'null' },
{ label : 'Preset', value : 'preset' },
{ label : 'Random', value : 'random' } ]
},
directed : {
label : 'Directed/Undirected',
help : 'Select a kind of edge.',
type : 'select',
display : 'radio',
value : '',
data : [ { label : 'Directed', value : 'triangle' },
{ label : 'Undirected', value : '' } ]
},
search_algorithm : {
label : 'Graph algorithms',
help : 'Select a search algorithm. For Breadth First Search and Depth First Search, please click on any node of the graph. For A*, please click on two nodes, one for the root and another for the destination.',
type : 'select',
display : 'radio',
value : '',
data : [ { label : 'Breadth First Search', value : 'bfs' },
{ label : 'Depth First Search', value : 'dfs' },
{ label : 'Minimum Spanning Tree (Kruskal)', value : 'kruskal' },
{ label : 'A*', value : 'astar' },
{ label : 'None', value : '' } ]
},
graph_traversal: {
label : 'Graph traversal',
help : 'To select a graph traversal type, please click on any node of the graph',
type : 'select',
display : 'radio',
value : '',
data : [ { label : 'Successors', value : 'successors' },
{ label : 'Predecessors', value : 'predecessors' },
{ label : 'Outgoers', value : 'outgoers' },
{ label : 'Incomers', value : 'incomers' },
{ label : 'Roots', value : 'roots' },
{ label : 'Leaves', value : 'leaves' },
{ label : 'None', value : '' } ]
},
color_picker_nodes : {
label : 'Select a color for nodes',
type : 'color',
value : '#548DB8'
},
color_picker_edges : {
label : 'Select a color for edges',
type : 'color',
value : '#A5A5A5'
},
color_picker_highlighted : {
label : 'Select a color for highlighted nodes and edges',
type : 'color',
value : '#C00000'
}
}
}
});
Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

@@ -0,0 +1,196 @@
define( [ 'utilities/utils', 'utilities/sifjson', 'plugins/cytoscape/cytoscape' ], function( Utils, SIF, Cytoscape ) {
return Backbone.Model.extend({
initialize: function( options ) {
var self = this,
chart = options.chart,
dataset = options.dataset,
settings = options.chart.settings,
data_content = null,
cytoscape = null,
astar_root = "",
astar_destination = "",
sif_file_ext = "sif",
highlighted_color = settings.get( 'color_picker_highlighted' );
Utils.get( {
url : dataset.download_url,
success : function( content ) {
// Select data for the graph
if( dataset.file_ext === sif_file_ext ) {
data_content = SIF.SIFJS.parse( content ).content;
}
else {
data_content = content.elements ? content.elements : content;
}
try {
cytoscape = Cytoscape({
container: document.getElementById( options.targets[ 0 ] ),
layout: {
name: settings.get( 'layout_name' ),
idealEdgeLength: 100,
nodeOverlap: 20
},
minZoom: 0.1,
maxZoom: 20,
style: [{
selector: 'node',
style: {
'background-color': settings.get( 'color_picker_nodes' ),
'opacity': 1,
'content': 'data(id)',
'text-valign': 'center',
}
},
{
selector: 'core',
style: {
'selection-box-color':'#AAD8FF',
'selection-box-border-color':'#8BB0D0',
'selection-box-opacity':'0.5'
}
},
{
selector: 'edge',
style: {
'curve-style': settings.get( 'curve_style' ),
'haystack-radius': 0,
'width': 3,
'opacity': 1,
'line-color': settings.get( 'color_picker_edges' ),
'target-arrow-shape': settings.get( 'directed' ),
"overlay-padding":"3px"
}
},
{
selector:'node:selected',
style: {
"border-width": "6px",
"border-color": "#AAD8FF",
"border-opacity": "0.5",
"background-color": "#77828C",
"text-outline-color": "#77828C"
}
},
{
selector: '.searchpath',
style: {
'background-color': highlighted_color,
'line-color': highlighted_color,
'target-arrow-color': highlighted_color,
'transition-property': 'background-color, line-color, target-arrow-color',
'transition-duration': '0.5s'
}
}],
elements: data_content // Set the JSON data for viewing
});
// Highlight the minimum spanning tree found using Kruskal algorithm
if( settings.get( 'search_algorithm' ) === "kruskal" ) {
var kruskal = cytoscape.elements().kruskal();
kruskal.edges().addClass( 'searchpath' );
}
// Register tap (clicking a node) event on graph nodes
// On tapping any node, BFS or DFS start from that node
cytoscape.$( 'node' ).on('tap', function( e ) {
var ele = e.cyTarget,
search_algorithm = settings.get( 'search_algorithm' ),
traversal_type = settings.get( 'graph_traversal' );
// If search algorithm and traversal both are chosen,
// search algorithm will take preference
if( settings.get( 'search_algorithm' ) !== "" ) {
self.run_search_algorithm( cytoscape, ele.id(), search_algorithm, self );
}
else if( settings.get( 'graph_traversal' ) !== "" ) {
self.run_traversal_type( cytoscape, ele.id(), traversal_type );
}
});
chart.state( 'ok', 'Chart drawn.' );
// Re-renders the graph view when window is resized
$( window ).resize( function() { cytoscape.layout(); } );
} catch( err ) {
chart.state( 'failed', err );
}
options.process.resolve();
},
error: function() {
chart.state( 'failed', 'Failed to access dataset.' );
options.process.resolve();
}
});
},
run_search_algorithm: function( cytoscape, root_id, type, self ) {
var algorithm = "", i = 0;
var selectNextElement = function() {
if( i < algorithm.path.length ) {
// Add css class for the selected edge(s)
algorithm.path[i].addClass( 'searchpath' );
i++;
// Animate the edges and nodes coloring
// of the path with a delay of 500ms
setTimeout( selectNextElement, 500 );
}
};
switch( type ) {
// Breadth First Search
case "bfs":
algorithm = cytoscape.elements().bfs( '#' + root_id, function() { }, true );
selectNextElement();
break;
// Depth First Search
case "dfs":
algorithm = cytoscape.elements().dfs( '#' + root_id, function() { }, true );
selectNextElement();
break;
// A* search
case "astar":
// Choose root and destination for performing A*
if( !self.astar_root ) {
self.astar_root = root_id;
}
else {
self.astar_destination = root_id;
}
if( self.astar_root && self.astar_destination ) {
algorithm = cytoscape.elements().aStar({ root: "#" + self.astar_root, goal: "#" + self.astar_destination },function() {}, true);
selectNextElement();
}
default:
return;
}
},
run_traversal_type: function( cytoscape, root_id, type ) {
var node_collection;
switch( type ) {
// Recursively get edges (and their sources) coming into the nodes in a collection
case "predecessors":
node_collection = cytoscape.$( '#' + root_id ).predecessors();
break;
// Recursively get edges (and their targets) coming out of the nodes in a collection
case "successors":
node_collection = cytoscape.$( '#' + root_id ).successors();
break;
// Get edges (and their targets) coming out of the nodes in a collection.
case "outgoers":
node_collection = cytoscape.$( '#' + root_id ).outgoers();
break;
// Get edges (and their sources) coming into the nodes in a collection.
case "incomers":
node_collection = cytoscape.$( '#' + root_id ).incomers();
break;
// From the set of calling nodes, get the nodes which are roots
case "roots":
node_collection = cytoscape.$( '#' + root_id ).roots();
break;
// From the set of calling nodes, get the nodes which are leaves
case "leaves":
node_collection = cytoscape.$( '#' + root_id ).leaves();
break;
default:
return;
}
// Add CSS class for selected nodes and edges
node_collection.edges().addClass( 'searchpath' );
node_collection.nodes().addClass( 'searchpath' );
}
});
});
File diff suppressed because one or more lines are too long