aboutsummaryrefslogtreecommitdiff
path: root/wqflask
diff options
context:
space:
mode:
Diffstat (limited to 'wqflask')
-rw-r--r--wqflask/wqflask/ctl/ctl_analysis.py53
-rw-r--r--wqflask/wqflask/static/new/javascript/ctl_graph.js199
-rw-r--r--wqflask/wqflask/templates/ctl_results.html36
-rw-r--r--wqflask/wqflask/templates/ctl_setup.html8
4 files changed, 288 insertions, 8 deletions
diff --git a/wqflask/wqflask/ctl/ctl_analysis.py b/wqflask/wqflask/ctl/ctl_analysis.py
index 7a42b2f8..3d2d7a37 100644
--- a/wqflask/wqflask/ctl/ctl_analysis.py
+++ b/wqflask/wqflask/ctl/ctl_analysis.py
@@ -6,6 +6,8 @@ import scipy as sp # SciPy
import rpy2.robjects as ro # R Objects
import rpy2.rinterface as ri
+import simplejson as json
+
from base.webqtlConfig import GENERATED_IMAGE_DIR
from utility import webqtlUtil # Random number for the image
from utility import genofile_parser # genofile_parser
@@ -73,8 +75,30 @@ class CTL(object):
self.r_CTLnetwork = ro.r["CTLnetwork"] # Map the CTLnetwork function
self.r_CTLprofiles = ro.r["CTLprofiles"] # Map the CTLprofiles function
self.r_plotCTLobject = ro.r["plot.CTLobject"] # Map the CTLsignificant function
+ self.nodes_list = []
+ self.edges_list = []
print("Obtained pointers to CTL functions")
+ def addNode(self, gt):
+ node_dict = { 'data' : {'id' : str(gt.name) + ":" + str(gt.dataset.name),
+ 'sid' : str(gt.name),
+ 'dataset' : str(gt.dataset.name),
+ 'label' : gt.name,
+ 'symbol' : gt.symbol,
+ 'geneid' : gt.geneid,
+ 'omim' : gt.omim } }
+ self.nodes_list.append(node_dict)
+
+ def addEdge(self, gtS, gtT, significant, x):
+ edge_data = {'id' : str(gtS.symbol) + '_' + significant[1][x] + '_' + str(gtT.symbol),
+ 'source' : str(gtS.name) + ":" + str(gtS.dataset.name),
+ 'target' : str(gtT.name) + ":" + str(gtT.dataset.name),
+ 'lod' : significant[3][x],
+ 'color' : "#ff0000",
+ 'width' : significant[3][x] }
+ edge_dict = { 'data' : edge_data }
+ self.edges_list.append(edge_dict)
+
def run_analysis(self, requestform):
print("Starting CTL analysis on dataset")
self.trait_db_list = [trait.strip() for trait in requestform['trait_list'].split(',')]
@@ -99,7 +123,7 @@ class CTL(object):
genofilelocation = locate(dataset.group.name + ".geno", "genotype")
parser = genofile_parser.ConvertGenoFile(genofilelocation)
parser.process_csv()
-
+ print(dataset.group)
# Create a genotype matrix
individuals = parser.individuals
markers = []
@@ -129,9 +153,11 @@ class CTL(object):
rPheno = r_t(ro.r.matrix(r_as_numeric(r_unlist(traits)), nrow=len(self.trait_db_list), ncol=len(individuals), dimnames = r_list(self.trait_db_list, individuals), byrow=True))
+ print(rPheno)
+
# Use a data frame to store the objects
- rPheno = r_data_frame(rPheno)
- rGeno = r_data_frame(rGeno)
+ rPheno = r_data_frame(rPheno, check_names = False)
+ rGeno = r_data_frame(rGeno, check_names = False)
# Debug: Print the genotype and phenotype files to disk
#r_write_table(rGeno, "~/outputGN/geno.csv")
@@ -156,7 +182,7 @@ class CTL(object):
self.r_lineplot(res, significance = significance)
r_dev_off()
- n = 2
+ n = 2 # We start from 2, since R starts from 1 :)
for trait in self.trait_db_list:
# Create the QTL like CTL plots
self.results['imgurl' + str(n)] = webqtlUtil.genRandStr("CTL_") + ".png"
@@ -169,6 +195,24 @@ class CTL(object):
# Flush any output from R
sys.stdout.flush()
+ # Create the interactive graph for cytoscape visualization (Nodes and Edges)
+ print(type(significant))
+ if not type(significant) == ri.RNULLType:
+ for x in range(len(significant[0])):
+ print(significant[0][x], significant[1][x], significant[2][x]) # Debug to console
+ tsS = significant[0][x].split(':') # Source
+ tsT = significant[2][x].split(':') # Target
+ gtS = TRAIT.GeneralTrait(name = tsS[0], dataset_name = tsS[1]) # Retrieve Source info from the DB
+ gtT = TRAIT.GeneralTrait(name = tsT[0], dataset_name = tsT[1]) # Retrieve Target info from the DB
+ self.addNode(gtS)
+ self.addNode(gtT)
+ self.addEdge(gtS, gtT, significant, x)
+
+ significant[0][x] = gtS.symbol + " (" + gtS.name + ")" # Update the trait name for the displayed table
+ significant[2][x] = gtT.symbol + " (" + gtT.name + ")" # Update the trait name for the displayed table
+
+ self.elements = json.dumps(self.nodes_list + self.edges_list)
+
def loadImage(self, path, name):
print("pre-loading imgage results:", self.results[path])
imgfile = open(self.results[path], 'rb')
@@ -188,6 +232,7 @@ class CTL(object):
print("Processing CTL output")
template_vars = {}
template_vars["results"] = self.results
+ template_vars["elements"] = self.elements
self.render_image(self.results)
sys.stdout.flush()
return(dict(template_vars))
diff --git a/wqflask/wqflask/static/new/javascript/ctl_graph.js b/wqflask/wqflask/static/new/javascript/ctl_graph.js
new file mode 100644
index 00000000..94bd7e9d
--- /dev/null
+++ b/wqflask/wqflask/static/new/javascript/ctl_graph.js
@@ -0,0 +1,199 @@
+window.onload=function() {
+ // id of Cytoscape Web container div
+ //var div_id = "cytoscapeweb";
+
+ var cy = cytoscape({
+ container: $('#cytoscapeweb'), // container to render in
+
+ elements: elements_list,
+
+ style: [ // the stylesheet for the graph
+ {
+ selector: 'node',
+ style: {
+ 'background-color': '#666',
+ 'label': 'data(symbol)',
+ 'font-size': 10
+ }
+ },
+
+ {
+ selector: 'edge',
+ style: {
+ 'width': 'data(width)',
+ 'line-color': 'data(color)',
+ 'target-arrow-color': '#ccc',
+ 'target-arrow-shape': 'none',
+ 'font-size': 8,
+ 'curve-style': 'bezier'
+ }
+ }
+ ],
+
+ zoom: 12,
+ layout: { name: 'circle',
+ fit: true, // whether to fit the viewport to the graph
+ padding: 30 // the padding on fit
+ //idealEdgeLength: function( edge ){ return edge.data['correlation']*10; },
+ },
+
+
+ zoomingEnabled: true,
+ userZoomingEnabled: true,
+ panningEnabled: true,
+ userPanningEnabled: true,
+ boxSelectionEnabled: false,
+ selectionType: 'single',
+
+ // rendering options:
+ styleEnabled: true
+ });
+
+ var eles = cy.$() // var containing all elements, so elements can be restored after being removed
+
+ var defaults = {
+ zoomFactor: 0.05, // zoom factor per zoom tick
+ zoomDelay: 45, // how many ms between zoom ticks
+ minZoom: 0.1, // min zoom level
+ maxZoom: 10, // max zoom level
+ fitPadding: 30, // padding when fitting
+ panSpeed: 10, // how many ms in between pan ticks
+ panDistance: 10, // max pan distance per tick
+ panDragAreaSize: 75, // the length of the pan drag box in which the vector for panning is calculated (bigger = finer control of pan speed and direction)
+ panMinPercentSpeed: 0.25, // the slowest speed we can pan by (as a percent of panSpeed)
+ panInactiveArea: 8, // radius of inactive area in pan drag box
+ panIndicatorMinOpacity: 0.5, // min opacity of pan indicator (the draggable nib); scales from this to 1.0
+ zoomOnly: false, // a minimal version of the ui only with zooming (useful on systems with bad mousewheel resolution)
+ fitSelector: undefined, // selector of elements to fit
+ animateOnFit: function(){ // whether to animate on fit
+ return false;
+ },
+ fitAnimationDuration: 1000, // duration of animation on fit
+
+ // icon class names
+ sliderHandleIcon: 'fa fa-minus',
+ zoomInIcon: 'fa fa-plus',
+ zoomOutIcon: 'fa fa-minus',
+ resetIcon: 'fa fa-expand'
+ };
+
+ cy.panzoom( defaults );
+
+ function create_qtips(cy){
+ cy.nodes().qtip({
+ content: function(){
+ gn_link = '<b>'+'<a href="http://gn2.genenetwork.org/show_trait?trait_id=' + this.data().sid + '&dataset=' + this.data().dataset + '" >'+this.data().id +'</a>'+'</b><br>'
+ ncbi_link = '<a href="http://www.ncbi.nlm.nih.gov/entrez/query.fcgi?db=gene&cmd=Retrieve&dopt=Graphics&list_uids=' + this.data().geneid + '" >NCBI<a>'+'<br>'
+ omim_link = '<a href="http://www.ncbi.nlm.nih.gov/omim/' + this.data().omim + '" >OMIM<a>'+'<br>'
+ qtip_content = gn_link + ncbi_link + omim_link
+ return qtip_content
+ //return '<b>'+'<a href="http://gn2.genenetwork.org/show_trait?trait_id=' + this.data().id + '&dataset=' + this.data().dataset + '" >'+this.data().id +'<a>'+'</b>'
+ },
+ // content: {
+ // title: '<b>'+'<a href="http://gn2.genenetwork.org/show_trait?trait_id=' + this.target() + '&dataset=' + this.dataset() + '" >'+this.target() +'<a>'+'</b>',
+ // text: this.target,
+ // button: true
+ // },
+ position: {
+ my: 'top center',
+ at: 'bottom center'
+ },
+ style: {
+ classes: 'qtip-bootstrap',
+ tip: {
+ width: 16,
+ height: 8
+ }
+ }
+ });
+
+ cy.edges().qtip({
+ content: function(){
+ edge_ID = '<b>Edge: ' + this.data().id + '</b><br>'
+ lod_score = 'LOD: ' + this.data().lod + '<br>'
+ return edge_ID + lod_score
+ },
+ position: {
+ my: 'top center',
+ at: 'bottom center'
+ },
+ style: {
+ classes: 'qtip-bootstrap',
+ tip: {
+ width: 16,
+ height: 8
+ }
+ }
+ });
+ }
+
+ create_qtips(cy)
+
+ $('#slide').change(function() {
+ eles.restore()
+
+ console.log(eles)
+
+ // nodes_to_restore = eles.filter("node[max_corr >= " + $(this).val() + "], edge[correlation >= " + $(this).val() + "][correlation <= -" + $(this).val() + "]")
+ // nodes_to_restore.restore()
+
+ // edges_to_restore = eles.filter("edge[correlation >= " + $(this).val() + "][correlation <= -" + $(this).val() + "]")
+ // edges_to_restore.restore()
+
+ //cy.$("node[max_corr >= " + $(this).val() + "]").restore();
+ //cy.$("edge[correlation >= " + $(this).val() + "][correlation <= -" + $(this).val() + "]").restore();
+
+ cy.$("node[max_corr < " + $(this).val() + "]").remove();
+ cy.$("edge[correlation < " + $(this).val() + "][correlation > -" + $(this).val() + "]").remove();
+
+ cy.layout({ name: $('select[name=layout_select]').val(),
+ fit: true, // whether to fit the viewport to the graph
+ padding: 25 // the padding on fit
+ });
+
+ });
+
+ $('#reset_graph').click(function() {
+ eles.restore()
+ $('#slide').val(0)
+ cy.layout({ name: $('select[name=layout_select]').val(),
+ fit: true, // whether to fit the viewport to the graph
+ padding: 25 // the padding on fit
+ });
+ });
+
+ $('select[name=focus_select]').change(function() {
+ focus_trait = $(this).val()
+
+ eles.restore()
+ cy.$('edge[source != "' + focus_trait + '"][target != "' + focus_trait + '"]').remove()
+
+ cy.layout({ name: $('select[name=layout_select]').val(),
+ fit: true, // whether to fit the viewport to the graph
+ padding: 25 // the padding on fit
+ });
+ });
+
+ $('select[name=layout_select]').change(function() {
+ layout_type = $(this).val()
+ console.log("LAYOUT:", layout_type)
+ cy.layout({ name: layout_type,
+ fit: true, // whether to fit the viewport to the graph
+ padding: 25 // the padding on fit
+ });
+ });
+
+ $("a#image_link").click(function(e) {
+ var pngData = cy.png();
+
+ $(this).attr('href', pngData);
+ $(this).attr('download', 'network_graph.png');
+
+ console.log("TESTING:", image_link)
+
+ });
+
+
+};
+
+
diff --git a/wqflask/wqflask/templates/ctl_results.html b/wqflask/wqflask/templates/ctl_results.html
index 00ccecb6..969ca18a 100644
--- a/wqflask/wqflask/templates/ctl_results.html
+++ b/wqflask/wqflask/templates/ctl_results.html
@@ -1,17 +1,30 @@
{% extends "base.html" %}
+{% block css %}
+ <link rel="stylesheet" type="text/css" href="/static/new/css/network_graph.css" />
+ <link rel="stylesheet" type="text/css" href="/static/packages/cytoscape/css/cytoscape.js-panzoom.css" />
+ <link rel="stylesheet" type="text/css" href="http://cdnjs.cloudflare.com/ajax/libs/qtip2/2.2.0/jquery.qtip.css">
+ <style>
+ /* The Cytoscape Web container must have its dimensions set. */
+ html, body { height: 100%; width: 100%; padding: 0; margin: 0; }
+ #cytoscapeweb { width: 70%; height: 70%; }
+ </style>
+{% endblock %}
+
{% block title %}CTL results{% endblock %}
{% block content %} <!-- Start of body -->
<div class="container">
<h1>CTL Results</h1>
{{(request.form['trait_list'].split(',')|length)}} phenotypes as input<br>
- <h3>Network Figure</h3>
+
+ <!--
<a href="/tmp/{{ results['imgurl1'] }}">
<img alt="Embedded Image" src="data:image/png;base64,
{% for elem in results['imgdata1'] -%}
{% print("%c"|format(elem)) %}
{%- endfor %}
- " /></a>
+ " /></a> -->
+
<h3>CTL/QTL Plots for individual traits</h3>
{% for r in range(2, (request.form['trait_list'].split(',')|length +1)) %}
<a href="/tmp/{{ results['imgurl' + r|string] }}">
@@ -39,9 +52,26 @@
</tr>
{% endfor %}
</table>
+ <h3>Network Figure</h3>
+ <div id="cytoscapeweb" class="col-xs-9" style="min-height:700px !important;"></div>
+</div>
+{% endblock %}
+{% block js %}
+ <script>
+ elements_list = {{ elements | safe }}
+ </script>
+ <script language="javascript" type="text/javascript" src="/static/new/packages/DataTables/js/jquery.js"></script>
+ <script language="javascript" type="text/javascript" src="http://cdnjs.cloudflare.com/ajax/libs/qtip2/2.2.0/jquery.qtip.js"></script>
+ <script language="javascript" type="text/javascript" src="/static/packages/underscore/underscore-min.js"></script>
+ <script language="javascript" type="text/javascript" src="/static/packages/cytoscape/js/min/cytoscape.min.js"></script>
+ <script language="javascript" type="text/javascript" src="/static/packages/cytoscape/js/min/AC_OETags.min.js"></script>
+ <script language="javascript" type="text/javascript" src="/static/packages/cytoscape/js/min/json2.min.js"></script>
+ <script language="javascript" type="text/javascript" src="/static/packages/cytoscape/js/src/cytoscape-panzoom.js"></script>
+ <script language="javascript" type="text/javascript" src="/static/packages/cytoscape/js/src/cytoscape-qtip.js"></script>
-</div>
+ <script language="javascript" type="text/javascript" src="/static/new/javascript/ctl_graph.js"></script>
{% endblock %}
+
diff --git a/wqflask/wqflask/templates/ctl_setup.html b/wqflask/wqflask/templates/ctl_setup.html
index a05379a8..992494dd 100644
--- a/wqflask/wqflask/templates/ctl_setup.html
+++ b/wqflask/wqflask/templates/ctl_setup.html
@@ -11,7 +11,13 @@
Please make sure you select enough traits to perform CTL. Your collection needs to contain at least 2 different traits. You provided {{request.form['trait_list'].split(',')|length}} traits as input.
</div>
{% else %}
- <h1>CTL analysis parameters</h1>
+ <h1>CTL analysis</h1>
+ CTL analysis is published as open source software, if you are using this method in your publications, please cite:<br><br>
+ Arends D, Li Y, Brockmann GA, Jansen RC, Williams RW, Prins P<br>
+ Correlation trait locus (CTL) mapping: Phenotype network inference subject to genotype.<br>
+ The Journal of Open Source Software (2016)<br>
+ <a href="http://joss.theoj.org/papers/10.21105/joss.00087">http://joss.theoj.org/papers/10.21105/joss.00087</a>
+ <br><br>
{{(request.form['trait_list'].split(',')|length)}} traits as input
<form action="/ctl_results" method="post" class="form-horizontal">