Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Code to fetch network from the db is optimized and multiple bugs have…
… been fixed !!
  • Loading branch information
proost committed Aug 14, 2015
1 parent 3a49da6 commit 6a5dc0e
Show file tree
Hide file tree
Showing 4 changed files with 88 additions and 30 deletions.
97 changes: 71 additions & 26 deletions planet/controllers/expression_network.py
@@ -1,39 +1,51 @@
from flask import Blueprint, redirect, url_for, render_template, Response
from sqlalchemy.sql import or_, and_
from flask import Blueprint, url_for, render_template, flash, redirect
from sqlalchemy.sql import and_

from planet.models.expression_networks import ExpressionNetworkMethod, ExpressionNetwork

import json


expression_network = Blueprint('expression_network', __name__)


@expression_network.route('/')
def expression_network_overview():
"""
Overview of all networks in the current database with basic information
"""
networks = ExpressionNetworkMethod.query.all()

return render_template("expression_network.html", networks=networks)


def __process_link(link):
output = {}
if link["gene_id"] is not None:
output = {"data": {"id": link["probe_name"],
"name": link["probe_name"],
"gene_link": url_for('sequence.sequence_view', sequence_id=link["gene_id"]),
"gene_name": link["gene_name"],
"node_type": "linked"}}
else:
output = {"data": {"id": link["probe_name"],
"name": link["probe_name"],
"gene_link": url_for('sequence.sequence_view', sequence_id=""),
"gene_name": link["gene_name"],
"node_type": "linked"}}
@expression_network.route('/view/<node_id>')
@expression_network.route('/view/<node_id>/<int:depth>')
def expression_network_view(node_id, depth=0):
"""
Page that displays the network graph for a specific network's probe, the depth indicates how many steps away from
the query gene the network is retrieved. For performance reasons depths > 2 are not allowed
:param node_id: id of the network's probe (the query) to visualize
:param depth: How many steps to include, 0 only the query and the direct neighborhood, 1 a step further, ...
"""
if depth > 2:
flash("Depth cannot be larger than 2. Showing the network with depth 2", "warning")
return redirect(url_for('expression_network.expression_network_view', node_id=node_id, depth=2))

node = ExpressionNetwork.query.get(node_id)
return render_template("expression_graph.html", node=node, depth=depth)

return output

@expression_network.route('/json/<node_id>')
@expression_network.route('/json/<node_id>/<int:depth>')
def expression_network_json(node_id, depth=0):
"""
Generates JSON output compatible with cytoscape.js (see planet/static/planet_graph.js for details how to render)
:param node_id: id of the network's probe (the query) to visualize
:param depth: How many steps to include, 0 only the query and the direct neighborhood, 1 a step further, ...
"""
node = ExpressionNetwork.query.get(node_id)
links = json.loads(node.network)

Expand All @@ -44,7 +56,8 @@ def expression_network_json(node_id, depth=0):
"name": node.probe,
"gene_link": url_for('sequence.sequence_view', sequence_id=node.gene_id),
"gene_name": node.gene.name,
"node_type": "query"}}]
"node_type": "query",
"color": "#888"}}]
edges = []

# lists necessary for doing deeper searches
Expand All @@ -53,9 +66,14 @@ def expression_network_json(node_id, depth=0):
existing_nodes = [node.probe]

# add direct neighbors of the gene of interest

for link in links:
nodes.append(__process_link(link))
edges.append({"data": {"source": node.probe, "target": link["probe_name"], "depth": 0}})
edges.append({"data": {"source": node.probe,
"target": link["probe_name"],
"depth": 0,
"link_score": link["link_score"],
"color": "#CCC"}})
additional_nodes.append(link["probe_name"])
existing_edges.append([node.probe, link["probe_name"]])
existing_edges.append([link["probe_name"], node.probe])
Expand All @@ -78,7 +96,11 @@ def expression_network_json(node_id, depth=0):
next_nodes.append(link["probe_name"])

if [new_node.probe, link["probe_name"]] not in existing_edges:
edges.append({"data": {"source": new_node.probe, "target": link["probe_name"], "depth": i}})
edges.append({"data": {"source": new_node.probe,
"target": link["probe_name"],
"depth": i,
"link_score": link["link_score"],
"color": "#CCC"}})
existing_edges.append([new_node.probe, link["probe_name"]])
existing_edges.append([link["probe_name"], new_node.probe])

Expand All @@ -92,15 +114,38 @@ def expression_network_json(node_id, depth=0):
for link in new_links:
if link["probe_name"] in existing_nodes:
if [new_node.probe, link["probe_name"]] not in existing_edges:
edges.append({"data": {"source": new_node.probe, "target": link["probe_name"], "depth": depth+1}})
edges.append({"data": {"source": new_node.probe,
"target": link["probe_name"],
"depth": depth+1,
"link_score": link["link_score"],
"color": "#CCC"}})
existing_edges.append([new_node.probe, link["probe_name"]])
existing_edges.append([link["probe_name"], new_node.probe])

return json.dumps({"nodes": nodes, "edges": edges})


@expression_network.route('/view/<node_id>')
@expression_network.route('/view/<node_id>/<int:depth>')
def expression_network_view(node_id, depth=0):
node = ExpressionNetwork.query.get(node_id)
return render_template("expression_graph.html", node=node, depth=depth)
def __process_link(linked_probe):
"""
Internal function that processes a linked probe (from the ExpressionNetwork.network field) to a data entry
compatible with cytoscape.js
:param linked_probe: hash with information from ExpressionNetwork.network field
:return: a hash formatted for use as a node with cytoscape.js
"""
if linked_probe["gene_id"] is not None:
return {"data": {"id": linked_probe["probe_name"],
"name": linked_probe["probe_name"],
"gene_link": url_for('sequence.sequence_view', sequence_id=linked_probe["gene_id"]),
"gene_name": linked_probe["gene_name"],
"node_type": "linked",
"color": "#888"}}
else:
return {"data": {"id": linked_probe["probe_name"],
"name": linked_probe["probe_name"],
"gene_link": url_for('sequence.sequence_view', sequence_id=""),
"gene_name": linked_probe["gene_name"],
"node_type": "linked",
"color": "#888"}}


10 changes: 6 additions & 4 deletions planet/static/js/planet_graph.js
Expand Up @@ -8,7 +8,8 @@ $('#cy').cytoscape({
.css({
'content': 'data(gene_name)',
'text-valign': 'center',
'color': 'white',
'color': '#FFF',
'background-color': 'data(color)',
'text-outline-width': 1,
'text-outline-color': '#888'
})
Expand All @@ -22,6 +23,8 @@ $('#cy').cytoscape({
.css({
'curve-style': 'haystack',
'opacity': 0.75,
'width': 'mapData(depth, 4, 0, 1, 5)',
'line-color': 'data(color)'
})
.selector(':selected')
.css({
Expand All @@ -38,16 +41,15 @@ $('#cy').cytoscape({
padding: 20
},

// on graph initial layout done (could be async depending on layout...)

ready: function(){
window.cy = this;

// giddy up...


cy.nodes().forEach(function(n){
var g = n.data('gene_link');

// code to add tooltips to the selected node
n.qtip({
content: [
{
Expand Down
Empty file added utils/__init__.py
Empty file.
11 changes: 11 additions & 0 deletions utils/color.py
@@ -0,0 +1,11 @@
"""
A set of functions designed to work with colors for websites
"""
import hashlib


def string_to_hex_color(input_string):
hashed_string = hashlib.sha1(str(input_string).encode('utf-8')).hexdigest()
color = "#" + hashed_string[0:3].upper()

return color

0 comments on commit 6a5dc0e

Please sign in to comment.