galaxy-commits
Threads by month
- ----- 2025 -----
- July
- June
- May
- April
- March
- February
- January
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2013 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2012 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2011 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2010 -----
- December
- November
- October
- September
- August
- July
- June
- May
- 15302 discussions

commit/galaxy-central: smcmanus: Moved galaxy.web.controllers references to galaxy.webapps.galaxy.controllers
by Bitbucket 05 Oct '12
by Bitbucket 05 Oct '12
05 Oct '12
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/changeset/210c39f4bf7f/
changeset: 210c39f4bf7f
user: smcmanus
date: 2012-10-05 03:43:15
summary: Moved galaxy.web.controllers references to galaxy.webapps.galaxy.controllers
affected #: 5 files
diff -r 2565580bb7cffd28c237ecafab1fbb46fe6185e9 -r 210c39f4bf7f2d91c68df84dd9ccecb2ff9f93aa templates/admin/requests/rename_datasets.mako
--- a/templates/admin/requests/rename_datasets.mako
+++ b/templates/admin/requests/rename_datasets.mako
@@ -1,7 +1,7 @@
<%inherit file="/base.mako"/><%namespace file="/message.mako" import="render_msg" />
-<% from galaxy.web.controllers.requests_admin import build_rename_datasets_for_sample_select_field %>
+<% from galaxy.webapps.galaxy.controllers.requests_admin import build_rename_datasets_for_sample_select_field %><h3>Rename datasets for Sample "${sample.name}"</h3>
diff -r 2565580bb7cffd28c237ecafab1fbb46fe6185e9 -r 210c39f4bf7f2d91c68df84dd9ccecb2ff9f93aa templates/library/common/browse_library_opt.mako
--- a/templates/library/common/browse_library_opt.mako
+++ b/templates/library/common/browse_library_opt.mako
@@ -214,7 +214,7 @@
## children, which are always lddas ). We also need to make sure we're displaying the latest version of this
## library_dataset, so we display the attributes from the ldda.
- from galaxy.web.controllers.library_common import branch_deleted
+ from galaxy.webapps.galaxy.controllers.library_common import branch_deleted
is_admin = trans.user_is_admin() and cntrller == 'library_admin'
current_version = ( ldda == library_dataset.library_dataset_dataset_association )
@@ -312,7 +312,7 @@
<%def name="render_folder( cntrller, folder, folder_pad, created_ldda_ids, library, hidden_folder_ids, tracked_datasets, show_deleted=False, parent=None, row_counter=None, root_folder=False, simple=False )"><%
- from galaxy.web.controllers.library_common import active_folders, active_folders_and_library_datasets, activatable_folders_and_library_datasets, map_library_datasets_to_lddas, branch_deleted, datasets_for_lddas
+ from galaxy.webapps.galaxy.controllers.library_common import active_folders, active_folders_and_library_datasets, activatable_folders_and_library_datasets, map_library_datasets_to_lddas, branch_deleted, datasets_for_lddas
# SM: DELETEME
from datetime import datetime, timedelta
@@ -472,7 +472,7 @@
<%def name="render_content(simple=False)"><%
from galaxy import util
- from galaxy.web.controllers.library_common import branch_deleted
+ from galaxy.webapps.galaxy.controllers.library_common import branch_deleted
from time import strftime
import logging
log = logging.getLogger( __name__ )
diff -r 2565580bb7cffd28c237ecafab1fbb46fe6185e9 -r 210c39f4bf7f2d91c68df84dd9ccecb2ff9f93aa templates/library/common/ldda_info.mako
--- a/templates/library/common/ldda_info.mako
+++ b/templates/library/common/ldda_info.mako
@@ -3,7 +3,7 @@
<%namespace file="/common/template_common.mako" import="render_template_fields" /><%
from galaxy import util
- from galaxy.web.controllers.library_common import branch_deleted, get_containing_library_from_library_dataset
+ from galaxy.webapps.galaxy.controllers.library_common import branch_deleted, get_containing_library_from_library_dataset
from galaxy.web.framework.helpers import time_ago
if ldda == ldda.library_dataset.library_dataset_dataset_association:
diff -r 2565580bb7cffd28c237ecafab1fbb46fe6185e9 -r 210c39f4bf7f2d91c68df84dd9ccecb2ff9f93aa templates/library/common/library_dataset_search_results.mako
--- a/templates/library/common/library_dataset_search_results.mako
+++ b/templates/library/common/library_dataset_search_results.mako
@@ -66,8 +66,7 @@
<%def name="render_content()"><%
from galaxy import util
- from galaxy.web.controllers.library_common import branch_deleted
- #from galaxy.webapps.galaxy.controllers.library_common import branch_deleted
+ from galaxy.webapps.galaxy.controllers.library_common import branch_deleted
from time import strftime
class RowCounter( object ):
diff -r 2565580bb7cffd28c237ecafab1fbb46fe6185e9 -r 210c39f4bf7f2d91c68df84dd9ccecb2ff9f93aa templates/webapps/reports/dataset_info.mako
--- a/templates/webapps/reports/dataset_info.mako
+++ b/templates/webapps/reports/dataset_info.mako
@@ -4,6 +4,7 @@
<%
from galaxy.web.framework.helpers import time_ago
from galaxy.web.controllers.library_common import get_containing_library_from_library_dataset
+ from galaxy.webapps.galaxy.controllers.library_common import get_containing_library_from_library_dataset
%>
%if message:
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0

05 Oct '12
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/changeset/2565580bb7cf/
changeset: 2565580bb7cf
user: smcmanus
date: 2012-10-05 02:48:46
summary: Cleanup: take out traceback and debug
affected #: 3 files
diff -r 029818b7e546a3b6835c49ef4f8694c5ac695dfb -r 2565580bb7cffd28c237ecafab1fbb46fe6185e9 lib/galaxy/webapps/galaxy/controllers/library_common.py
--- a/lib/galaxy/webapps/galaxy/controllers/library_common.py
+++ b/lib/galaxy/webapps/galaxy/controllers/library_common.py
@@ -143,8 +143,6 @@
message=message,
status=status )
except Exception, e:
- import traceback
- log.debug( "traceback: %s" % traceback.format_exc() )
message = 'Error attempting to display contents of library (%s): %s.' % ( str( library.name ), str( e ) )
status = 'error'
default_action = params.get( 'default_action', None )
diff -r 029818b7e546a3b6835c49ef4f8694c5ac695dfb -r 2565580bb7cffd28c237ecafab1fbb46fe6185e9 lib/galaxy/webapps/galaxy/controllers/requests_admin.py
--- a/lib/galaxy/webapps/galaxy/controllers/requests_admin.py
+++ b/lib/galaxy/webapps/galaxy/controllers/requests_admin.py
@@ -284,7 +284,6 @@
request_id = trans.security.encode_id( sample.request.id )
library_id = trans.security.encode_id( sample.library.id )
self.datatx_grid.title = 'Manage "%s" datasets' % sample.name
- log.debug( "!!!!!!!!!!!!!!!!!!!!!!@@@@@@@@@@@@@@@@@@@@@@@##################" )
self.datatx_grid.global_actions = [ grids.GridAction( "Browse target data library",
dict( controller='library_common',
action='browse_library',
diff -r 029818b7e546a3b6835c49ef4f8694c5ac695dfb -r 2565580bb7cffd28c237ecafab1fbb46fe6185e9 templates/library/common/library_dataset_search_results.mako
--- a/templates/library/common/library_dataset_search_results.mako
+++ b/templates/library/common/library_dataset_search_results.mako
@@ -67,6 +67,7 @@
<%
from galaxy import util
from galaxy.web.controllers.library_common import branch_deleted
+ #from galaxy.webapps.galaxy.controllers.library_common import branch_deleted
from time import strftime
class RowCounter( object ):
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0

05 Oct '12
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/changeset/029818b7e546/
changeset: 029818b7e546
user: smcmanus
date: 2012-10-05 02:43:55
summary: The browse_library.mako template referred to galaxy.web.controllers.library_common, which has been updated to galaxy.webapps.galaxy.controllers.library_common. The Data Library browsing should be fixed.
affected #: 3 files
diff -r f3b183e756f9b209ef0904718ed547e04c74ab7a -r 029818b7e546a3b6835c49ef4f8694c5ac695dfb lib/galaxy/webapps/galaxy/controllers/library_common.py
--- a/lib/galaxy/webapps/galaxy/controllers/library_common.py
+++ b/lib/galaxy/webapps/galaxy/controllers/library_common.py
@@ -131,7 +131,7 @@
comptypes = get_comptypes( trans )
try:
# SM: TODO: Add configuration variable asap.
- return trans.fill_template( '/library/common/browse_library.mako',
+ return trans.fill_template( 'library/common/browse_library.mako',
cntrller=cntrller,
use_panels=use_panels,
library=library,
@@ -143,6 +143,8 @@
message=message,
status=status )
except Exception, e:
+ import traceback
+ log.debug( "traceback: %s" % traceback.format_exc() )
message = 'Error attempting to display contents of library (%s): %s.' % ( str( library.name ), str( e ) )
status = 'error'
default_action = params.get( 'default_action', None )
diff -r f3b183e756f9b209ef0904718ed547e04c74ab7a -r 029818b7e546a3b6835c49ef4f8694c5ac695dfb lib/galaxy/webapps/galaxy/controllers/requests_admin.py
--- a/lib/galaxy/webapps/galaxy/controllers/requests_admin.py
+++ b/lib/galaxy/webapps/galaxy/controllers/requests_admin.py
@@ -284,6 +284,7 @@
request_id = trans.security.encode_id( sample.request.id )
library_id = trans.security.encode_id( sample.library.id )
self.datatx_grid.title = 'Manage "%s" datasets' % sample.name
+ log.debug( "!!!!!!!!!!!!!!!!!!!!!!@@@@@@@@@@@@@@@@@@@@@@@##################" )
self.datatx_grid.global_actions = [ grids.GridAction( "Browse target data library",
dict( controller='library_common',
action='browse_library',
diff -r f3b183e756f9b209ef0904718ed547e04c74ab7a -r 029818b7e546a3b6835c49ef4f8694c5ac695dfb templates/library/common/browse_library.mako
--- a/templates/library/common/browse_library.mako
+++ b/templates/library/common/browse_library.mako
@@ -213,7 +213,7 @@
## children, which are always lddas ). We also need to make sure we're displaying the latest version of this
## library_dataset, so we display the attributes from the ldda.
- from galaxy.web.controllers.library_common import branch_deleted
+ from galaxy.webapps.galaxy.controllers.library_common import branch_deleted
is_admin = trans.user_is_admin() and cntrller == 'library_admin'
@@ -312,7 +312,7 @@
<%def name="render_folder( cntrller, folder, folder_pad, created_ldda_ids, library, hidden_folder_ids, tracked_datasets, show_deleted=False, parent=None, row_counter=None, root_folder=False, simple=False )"><%
- from galaxy.web.controllers.library_common import active_folders, active_folders_and_library_datasets, activatable_folders_and_library_datasets, branch_deleted
+ from galaxy.webapps.galaxy.controllers.library_common import active_folders, active_folders_and_library_datasets, activatable_folders_and_library_datasets, branch_deleted
is_admin = trans.user_is_admin() and cntrller == 'library_admin'
has_accessible_library_datasets = trans.app.security_agent.has_accessible_library_datasets( trans, folder, trans.user, current_user_roles, search_downward=False )
@@ -472,7 +472,7 @@
<%def name="render_content(simple=False)"><%
from galaxy import util
- from galaxy.web.controllers.library_common import branch_deleted
+ from galaxy.webapps.galaxy.controllers.library_common import branch_deleted
from time import strftime
is_admin = trans.user_is_admin() and cntrller == 'library_admin'
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0

04 Oct '12
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/changeset/f3b183e756f9/
changeset: f3b183e756f9
user: jgoecks
date: 2012-10-04 18:35:16
summary: Pack scripts and add compiled template.
affected #: 3 files
diff -r 89c27f6b20f8f261a8e45e33abcc2ed9c1509a71 -r f3b183e756f9b209ef0904718ed547e04c74ab7a static/scripts/packed/templates/compiled/template-visualization-scatterplotControlForm.js
--- /dev/null
+++ b/static/scripts/packed/templates/compiled/template-visualization-scatterplotControlForm.js
@@ -0,0 +1,1 @@
+(function(){var b=Handlebars.template,a=Handlebars.templates=Handlebars.templates||{};a["template-visualization-scatterplotControlForm"]=b(function(g,n,f,m,l){f=f||g.helpers;var j="",d,i,h="function",k=this.escapeExpression,o=this;function e(t,s){var q="",r,p;q+='\n <option value="';p=f.index;if(p){r=p.call(t,{hash:{}})}else{r=t.index;r=typeof r===h?r():r}q+=k(r)+'">';p=f.name;if(p){r=p.call(t,{hash:{}})}else{r=t.name;r=typeof r===h?r():r}q+=k(r)+"</option>\n ";return q}function c(t,s){var q="",r,p;q+='\n <option value="';p=f.index;if(p){r=p.call(t,{hash:{}})}else{r=t.index;r=typeof r===h?r():r}q+=k(r)+'">';p=f.name;if(p){r=p.call(t,{hash:{}})}else{r=t.name;r=typeof r===h?r():r}q+=k(r)+"</option>\n ";return q}j+='\n<div id="loading-indicator" style="display: none;">\n <img class="loading-img" src="';i=f.loadingIndicatorImagePath;if(i){d=i.call(n,{hash:{}})}else{d=n.loadingIndicatorImagePath;d=typeof d===h?d():d}j+=k(d)+'" />\n <span class="loading-message"></span>\n</div>\n\n';j+='\n<div id="chart-settings">\n\n ';j+='\n <div id="x-column-input">\n <label for="">Data column for X: </label>\n <select name="x-column">\n ';d=n.availableColumns;d=f.each.call(n,d,{hash:{},inverse:o.noop,fn:o.program(1,e,l)});if(d||d===0){j+=d}j+='\n </select>\n </div>\n <div id="y-column-input">\n <label for="">Data column for Y: </label>\n <select name="y-column">\n ';d=n.availableColumns;d=f.each.call(n,d,{hash:{},inverse:o.noop,fn:o.program(3,c,l)});if(d||d===0){j+=d}j+='\n </select>\n </div>\n \n <input id="render-button" type="button" value="Draw" />\n <div class="clear"></div>\n</div>';return j})})();
\ No newline at end of file
diff -r 89c27f6b20f8f261a8e45e33abcc2ed9c1509a71 -r f3b183e756f9b209ef0904718ed547e04c74ab7a static/scripts/packed/viz/phyloviz.js
--- a/static/scripts/packed/viz/phyloviz.js
+++ b/static/scripts/packed/viz/phyloviz.js
@@ -1,1 +1,1 @@
-var UserMenuBase=Backbone.View.extend({className:"UserMenuBase",isAcceptableValue:function(e,c,a){var b=this,f=e.val(),g=e.attr("displayLabel")||e.attr("id").replace("phyloViz","");function d(h){return !isNaN(parseFloat(h))&&isFinite(h)}if(!d(f)){alert(g+" is not a number!");return false}if(f>a){alert(g+" is too large.");return false}else{if(f<c){alert(g+" is too small.");return false}}return true},hasIllegalJsonCharacters:function(a){if(a.val().search(/"|'|\\/)!==-1){alert("Named fields cannot contain these illegal characters: double quote(\"), single guote('), or back slash(\\). ");return true}return false}});function PhyloTreeLayout(){var j=this,e=d3.layout.hierarchy().sort(null).value(null),i=360,d="Linear",h=18,f=200,g=0,c=0.5,a=50;j.leafHeight=function(k){if(typeof k==="undefined"){return h}else{h=k;return j}};j.layoutMode=function(k){if(typeof k==="undefined"){return d}else{d=k;return j}};j.layoutAngle=function(k){if(typeof k==="undefined"){return i}if(isNaN(k)||k<0||k>360){return j}else{i=k;return j}};j.separation=function(k){if(typeof k==="undefined"){return f}else{f=k;return j}};j.links=function(k){return d3.layout.tree().links(k)};j.nodes=function(n,l){var m=e.call(j,n,l),k=[],p=0,o=0;m.forEach(function(q){var r=q.data;r.depth=q.depth;p=r.depth>p?r.depth:p;k.push(r)});k.forEach(function(q){if(!q.children){o+=1;q.depth=p}});h=d==="Circular"?i/o:h;g=0;b(k[0],p,h,null);return k};function b(o,q,n,m){var l=o.children,k=0;var p=o.dist||c;p=p>1?1:p;o.dist=p;if(m!==null){o.y0=m.y0+p*f}else{o.y0=a}if(!l){o.x0=g++*n}else{l.forEach(function(r){r.parent=o;k+=b(r,q,n,o)});o.x0=k/l.length}o.x=o.x0;o.y=o.y0;return o.x0}return j}var PhyloTree=Visualization.extend({defaults:{layout:"Linear",separation:250,leafHeight:18,type:"phyloviz",title:"Title",scaleFactor:1,translate:[0,0],fontSize:12,selectedNode:null,nodeAttrChangedTime:0},root:{},toggle:function(a){if(typeof a==="undefined"){return}if(a.children){a._children=a.children;a.children=null}else{a.children=a._children;a._children=null}},toggleAll:function(a){if(a.children&&a.children.length!==0){a.children.forEach(this.toggleAll);toggle(a)}},getData:function(){return this.root},save:function(){var a=this.root;b(a);this.set("root",a);function b(d){delete d.parent;if(d._selected){delete d._selected}d.children?d.children.forEach(b):0;d._children?d._children.forEach(b):0}var c=jQuery.extend(true,{},this.attributes);c.selectedNode=null;show_message("Saving to Galaxy","progress");return $.ajax({url:this.url(),type:"POST",dataType:"json",data:{vis_json:JSON.stringify(c)},success:function(d){var e=d.url.split("id=")[1].split("&")[0],f="/phyloviz/visualization?id="+e;window.history.pushState({},"",f+window.location.hash);hide_modal()}})}});var PhylovizLayoutBase=Backbone.View.extend({defaults:{nodeRadius:4.5},stdInit:function(b){var a=this;a.model.on("change:separation change:leafHeight change:fontSize change:nodeAttrChangedTime",a.updateAndRender,a);a.vis=b.vis;a.i=0;a.maxDepth=-1;a.width=b.width;a.height=b.height},updateAndRender:function(c){var b=d3.select(".vis"),a=this;c=c||a.model.root;a.renderNodes(c);a.renderLinks(c);a.addTooltips()},renderLinks:function(a){var j=this;var b=j.diagonal;var c=j.duration;var e=j.layoutMode;var g=j.vis.selectAll("g.completeLink").data(j.tree.links(j.nodes),function(k){return k.target.id});var i=function(k){k.pos0=k.source.y0+" "+k.source.x0;k.pos1=k.source.y0+" "+k.target.x0;k.pos2=k.target.y0+" "+k.target.x0};var h=g.enter().insert("svg:g","g.node").attr("class","completeLink");h.append("svg:path").attr("class","link").attr("d",function(k){i(k);return"M "+k.pos0+" L "+k.pos1});var f=g.transition().duration(500);f.select("path.link").attr("d",function(k){i(k);return"M "+k.pos0+" L "+k.pos1+" L "+k.pos2});var d=g.exit().remove()},selectNode:function(b){var a=this;d3.selectAll("g.node").classed("selectedHighlight",function(c){if(b.id===c.id){if(b._selected){delete b._selected;return false}else{b._selected=true;return true}}return false});a.model.set("selectedNode",b);$("#phyloVizSelectedNodeName").val(b.name);$("#phyloVizSelectedNodeDist").val(b.dist);$("#phyloVizSelectedNodeAnnotation").val(b.annotation||"")},addTooltips:function(){$(".bs-tooltip").remove();$(".node").attr("data-original-title",function(){var b=this.__data__,a=b.annotation||"None";return b?(b.name?b.name+"<br/>":"")+"Dist: "+b.dist+" <br/>Annotation: "+a:""}).tooltip({placement:"top",trigger:"hover"})}});var PhylovizLinearView=PhylovizLayoutBase.extend({initialize:function(b){var a=this;a.margins=b.margins;a.layoutMode="Linear";a.stdInit(b);a.layout();a.updateAndRender(a.model.root)},layout:function(){var a=this;a.tree=new PhyloTreeLayout().layoutMode("Linear");a.diagonal=d3.svg.diagonal().projection(function(b){return[b.y,b.x]})},renderNodes:function(a){var h=this,i=h.model.get("fontSize")+"px";h.tree.separation(h.model.get("separation")).leafHeight(h.model.get("leafHeight"));var d=500,b=h.tree.separation(h.model.get("separation")).nodes(h.model.root);var c=h.vis.selectAll("g.node").data(b,function(j){return j.name+j.id||(j.id=++h.i)});h.nodes=b;h.duration=d;var e=c.enter().append("svg:g").attr("class","node").on("dblclick",function(){d3.event.stopPropagation()}).on("click",function(j){if(d3.event.altKey){h.selectNode(j)}else{if(j.children&&j.children.length===0){return}h.model.toggle(j);h.updateAndRender(j)}});e.attr("transform",function(j){return"translate("+a.y0+","+a.x0+")"});e.append("svg:circle").attr("r",0.000001).style("fill",function(j){return j._children?"lightsteelblue":"#fff"});e.append("svg:text").attr("class","nodeLabel").attr("x",function(j){return j.children||j._children?-10:10}).attr("dy",".35em").attr("text-anchor",function(j){return j.children||j._children?"end":"start"}).style("fill-opacity",0.000001);var f=c.transition().duration(d);f.attr("transform",function(j){return"translate("+j.y+","+j.x+")"});f.select("circle").attr("r",h.defaults.nodeRadius).style("fill",function(j){return j._children?"lightsteelblue":"#fff"});f.select("text").style("fill-opacity",1).style("font-size",i).text(function(j){return j.name});var g=c.exit().transition().duration(d).remove();g.select("circle").attr("r",0.000001);g.select("text").style("fill-opacity",0.000001);b.forEach(function(j){j.x0=j.x;j.y0=j.y})}});var PhylovizView=Backbone.View.extend({className:"phyloviz",initialize:function(b){var a=this;a.MIN_SCALE=0.05;a.MAX_SCALE=5;a.MAX_DISPLACEMENT=500;a.margins=[10,60,10,80];a.width=$("#PhyloViz").width();a.height=$("#PhyloViz").height();a.radius=a.width;a.data=b.data;$(window).resize(function(){a.width=$("#PhyloViz").width();a.height=$("#PhyloViz").height();a.render()});a.phyloTree=new PhyloTree(b.config);a.phyloTree.root=a.data;a.zoomFunc=d3.behavior.zoom().scaleExtent([a.MIN_SCALE,a.MAX_SCALE]);a.zoomFunc.translate(a.phyloTree.get("translate"));a.zoomFunc.scale(a.phyloTree.get("scaleFactor"));a.navMenu=new HeaderButtons(a);a.settingsMenu=new SettingsMenu({phyloTree:a.phyloTree});a.nodeSelectionView=new NodeSelectionView({phyloTree:a.phyloTree});a.search=new PhyloVizSearch();setTimeout(function(){a.zoomAndPan()},1000)},render:function(){var b=this;$("#PhyloViz").empty();b.mainSVG=d3.select("#PhyloViz").append("svg:svg").attr("width",b.width).attr("height",b.height).attr("pointer-events","all").call(b.zoomFunc.on("zoom",function(){b.zoomAndPan()}));b.boundingRect=b.mainSVG.append("svg:rect").attr("class","boundingRect").attr("width",b.width).attr("height",b.height).attr("stroke","black").attr("fill","white");b.vis=b.mainSVG.append("svg:g").attr("class","vis");b.layoutOptions={model:b.phyloTree,width:b.width,height:b.height,vis:b.vis,margins:b.margins};$("#title").text("Phylogenetic Tree from "+b.phyloTree.get("title")+":");var a=new PhylovizLinearView(b.layoutOptions)},zoomAndPan:function(a){if(typeof a!=="undefined"){var g=a.zoom,c=a.translate}var j=this,e=j.zoomFunc.scale(),i=j.zoomFunc.translate(),f="",h="";switch(g){case"reset":e=1;i=[0,0];break;case"+":e*=1.1;break;case"-":e*=0.9;break;default:if(typeof g==="number"){e=g}else{if(d3.event!==null){e=d3.event.scale}}}if(e<j.MIN_SCALE||e>j.MAX_SCALE){return}j.zoomFunc.scale(e);f="translate("+j.margins[3]+","+j.margins[0]+") scale("+e+")";if(d3.event!==null){h="translate("+d3.event.translate+")"}else{if(typeof c!=="undefined"){var d=c.split(",")[0];var b=c.split(",")[1];if(!isNaN(d)&&!isNaN(b)){i=[i[0]+parseFloat(d),i[1]+parseFloat(b)]}}j.zoomFunc.translate(i);h="translate("+i+")"}j.phyloTree.set("scaleFactor",e);j.phyloTree.set("translate",i);j.vis.attr("transform",h+f)},reloadViz:function(){var b=this,d=$("#phylovizNexSelector :selected").val(),a=b.phyloTree.get("dataset_id"),c="phyloviz/getJsonData?dataset_id="+a+"&treeIndex="+String(d);$.getJSON(c,function(e){window.initPhyloViz(e.data,e.config)})}});var HeaderButtons=Backbone.View.extend({initialize:function(b){var a=this;a.phylovizView=b;$("#panelHeaderRightBtns").empty();$("#phyloVizNavBtns").empty();$("#phylovizNexSelector").off();a.initNavBtns();a.initRightHeaderBtns();$("#phylovizNexSelector").off().on("change",function(){a.phylovizView.reloadViz()})},initRightHeaderBtns:function(){var a=this;rightMenu=create_icon_buttons_menu([{icon_class:"gear",title:"PhyloViz Settings",on_click:function(){$("#SettingsMenu").show();a.settingsMenu.updateUI()}},{icon_class:"disk",title:"Save visualization",on_click:function(){var b=$("#phylovizNexSelector option:selected").text();if(b){a.phylovizView.phyloTree.set("title",b)}a.phylovizView.phyloTree.save()}},{icon_class:"chevron-expand",title:"Search / Edit Nodes",on_click:function(){$("#nodeSelectionView").show()}},{icon_class:"information",title:"Phyloviz Help",on_click:function(){window.open("http://wiki.g2.bx.psu.edu/Learn/Visualization/PhylogeneticTree")}}],{tooltip_config:{placement:"bottom"}});$("#panelHeaderRightBtns").append(rightMenu.$el)},initNavBtns:function(){var a=this,b=create_icon_buttons_menu([{icon_class:"zoom-in",title:"Zoom in",on_click:function(){a.phylovizView.zoomAndPan({zoom:"+"})}},{icon_class:"zoom-out",title:"Zoom out",on_click:function(){a.phylovizView.zoomAndPan({zoom:"-"})}},{icon_class:"arrow-circle",title:"Reset Zoom/Pan",on_click:function(){a.phylovizView.zoomAndPan({zoom:"reset"})}}],{tooltip_config:{placement:"bottom"}});$("#phyloVizNavBtns").append(b.$el)}});var SettingsMenu=UserMenuBase.extend({className:"Settings",initialize:function(b){var a=this;a.phyloTree=b.phyloTree;a.el=$("#SettingsMenu");a.inputs={separation:$("#phyloVizTreeSeparation"),leafHeight:$("#phyloVizTreeLeafHeight"),fontSize:$("#phyloVizTreeFontSize")};$("#settingsCloseBtn").off().on("click",function(){a.el.hide()});$("#phylovizResetSettingsBtn").off().on("click",function(){a.resetToDefaults()});$("#phylovizApplySettingsBtn").off().on("click",function(){a.apply()})},apply:function(){var a=this;if(!a.isAcceptableValue(a.inputs.separation,50,2500)||!a.isAcceptableValue(a.inputs.leafHeight,5,30)||!a.isAcceptableValue(a.inputs.fontSize,5,20)){return}$.each(a.inputs,function(b,c){a.phyloTree.set(b,c.val())})},updateUI:function(){var a=this;$.each(a.inputs,function(b,c){c.val(a.phyloTree.get(b))})},resetToDefaults:function(){$(".bs-tooltip").remove();var a=this;$.each(a.phyloTree.defaults,function(b,c){a.phyloTree.set(b,c)});a.updateUI()},render:function(){}});var NodeSelectionView=UserMenuBase.extend({className:"Settings",initialize:function(b){var a=this;a.el=$("#nodeSelectionView");a.phyloTree=b.phyloTree;a.UI={enableEdit:$("#phylovizEditNodesCheck"),saveChanges:$("#phylovizNodeSaveChanges"),cancelChanges:$("#phylovizNodeCancelChanges"),name:$("#phyloVizSelectedNodeName"),dist:$("#phyloVizSelectedNodeDist"),annotation:$("#phyloVizSelectedNodeAnnotation")};a.valuesOfConcern={name:null,dist:null,annotation:null};$("#nodeSelCloseBtn").off().on("click",function(){a.el.hide()});a.UI.saveChanges.off().on("click",function(){a.updateNodes()});a.UI.cancelChanges.off().on("click",function(){a.cancelChanges()});(function(c){c.fn.enable=function(d){return c(this).each(function(){if(d){c(this).removeAttr("disabled")}else{c(this).attr("disabled","disabled")}})}})(jQuery);a.UI.enableEdit.off().on("click",function(){a.toggleUI()})},toggleUI:function(){var a=this,b=a.UI.enableEdit.is(":checked");!b?a.cancelChanges():"";$.each(a.valuesOfConcern,function(c,d){a.UI[c].enable(b)});if(b){a.UI.saveChanges.show();a.UI.cancelChanges.show()}else{a.UI.saveChanges.hide();a.UI.cancelChanges.hide()}},cancelChanges:function(){var a=this,b=a.phyloTree.get("selectedNode");if(b){$.each(a.valuesOfConcern,function(c,d){a.UI[c].val(b[c])})}},updateNodes:function(){var a=this,b=a.phyloTree.get("selectedNode");if(b){if(!a.isAcceptableValue(a.UI.dist,0,1)||a.hasIllegalJsonCharacters(a.UI.name)||a.hasIllegalJsonCharacters(a.UI.annotation)){return}$.each(a.valuesOfConcern,function(c,d){(b[c])=a.UI[c].val()});a.phyloTree.set("nodeAttrChangedTime",new Date())}else{alert("No node selected")}}});var PhyloVizSearch=UserMenuBase.extend({initialize:function(){var a=this;$("#phyloVizSearchBtn").on("click",function(){var c=$("#phyloVizSearchTerm"),d=$("#phyloVizSearchCondition").val().split("-"),b=d[0],e=d[1];a.hasIllegalJsonCharacters(c);if(b==="dist"){a.isAcceptableValue(c,0,1)}a.searchTree(b,e,c.val())})},searchTree:function(a,c,b){d3.selectAll("g.node").classed("searchHighlight",function(f){var e=f[a];if(typeof e!=="undefined"&&e!==null){if(a==="dist"){switch(c){case"greaterEqual":return e>=+b;case"lesserEqual":return e<=+b;default:return}}else{if(a==="name"||a==="annotation"){return e.toLowerCase().indexOf(b.toLowerCase())!==-1}}}})}});
\ No newline at end of file
+define(["libs/d3","viz/visualization"],function(l,f){var k=Backbone.View.extend({className:"UserMenuBase",isAcceptableValue:function(q,o,m){var n=this,r=q.val(),s=q.attr("displayLabel")||q.attr("id").replace("phyloViz","");function p(t){return !isNaN(parseFloat(t))&&isFinite(t)}if(!p(r)){alert(s+" is not a number!");return false}if(r>m){alert(s+" is too large.");return false}else{if(r<o){alert(s+" is too small.");return false}}return true},hasIllegalJsonCharacters:function(m){if(m.val().search(/"|'|\\/)!==-1){alert("Named fields cannot contain these illegal characters: double quote(\"), single guote('), or back slash(\\). ");return true}return false}});function g(){var v=this,q=l.layout.hierarchy().sort(null).value(null),u=360,p="Linear",t=18,r=200,s=0,o=0.5,m=50;v.leafHeight=function(w){if(typeof w==="undefined"){return t}else{t=w;return v}};v.layoutMode=function(w){if(typeof w==="undefined"){return p}else{p=w;return v}};v.layoutAngle=function(w){if(typeof w==="undefined"){return u}if(isNaN(w)||w<0||w>360){return v}else{u=w;return v}};v.separation=function(w){if(typeof w==="undefined"){return r}else{r=w;return v}};v.links=function(w){return l.layout.tree().links(w)};v.nodes=function(z,x){var y=q.call(v,z,x),w=[],B=0,A=0;y.forEach(function(C){var D=C.data;D.depth=C.depth;B=D.depth>B?D.depth:B;w.push(D)});w.forEach(function(C){if(!C.children){A+=1;C.depth=B}});t=p==="Circular"?u/A:t;s=0;n(w[0],B,t,null);return w};function n(A,C,z,y){var x=A.children,w=0;var B=A.dist||o;B=B>1?1:B;A.dist=B;if(y!==null){A.y0=y.y0+B*r}else{A.y0=m}if(!x){A.x0=s++*z}else{x.forEach(function(D){D.parent=A;w+=n(D,C,z,A)});A.x0=w/x.length}A.x=A.x0;A.y=A.y0;return A.x0}return v}var b=f.Visualization.extend({defaults:{layout:"Linear",separation:250,leafHeight:18,type:"phyloviz",title:"Title",scaleFactor:1,translate:[0,0],fontSize:12,selectedNode:null,nodeAttrChangedTime:0},root:{},toggle:function(m){if(typeof m==="undefined"){return}if(m.children){m._children=m.children;m.children=null}else{m.children=m._children;m._children=null}},toggleAll:function(m){if(m.children&&m.children.length!==0){m.children.forEach(this.toggleAll);toggle(m)}},getData:function(){return this.root},save:function(){var m=this.root;n(m);this.set("root",m);function n(p){delete p.parent;if(p._selected){delete p._selected}if(p.children){p.children.forEach(n)}if(p._children){p._children.forEach(n)}}var o=jQuery.extend(true,{},this.attributes);o.selectedNode=null;show_message("Saving to Galaxy","progress");return $.ajax({url:this.url(),type:"POST",dataType:"json",data:{vis_json:JSON.stringify(o)},success:function(p){var q=p.url.split("id=")[1].split("&")[0],r="/phyloviz/visualization?id="+q;window.history.pushState({},"",r+window.location.hash);hide_modal()}})}});var d=Backbone.View.extend({defaults:{nodeRadius:4.5},stdInit:function(n){var m=this;m.model.on("change:separation change:leafHeight change:fontSize change:nodeAttrChangedTime",m.updateAndRender,m);m.vis=n.vis;m.i=0;m.maxDepth=-1;m.width=n.width;m.height=n.height},updateAndRender:function(o){var n=l.select(".vis"),m=this;o=o||m.model.root;m.renderNodes(o);m.renderLinks(o);m.addTooltips()},renderLinks:function(m){var v=this;var n=v.diagonal;var o=v.duration;var q=v.layoutMode;var s=v.vis.selectAll("g.completeLink").data(v.tree.links(v.nodes),function(w){return w.target.id});var u=function(w){w.pos0=w.source.y0+" "+w.source.x0;w.pos1=w.source.y0+" "+w.target.x0;w.pos2=w.target.y0+" "+w.target.x0};var t=s.enter().insert("svg:g","g.node").attr("class","completeLink");t.append("svg:path").attr("class","link").attr("d",function(w){u(w);return"M "+w.pos0+" L "+w.pos1});var r=s.transition().duration(500);r.select("path.link").attr("d",function(w){u(w);return"M "+w.pos0+" L "+w.pos1+" L "+w.pos2});var p=s.exit().remove()},selectNode:function(n){var m=this;l.selectAll("g.node").classed("selectedHighlight",function(o){if(n.id===o.id){if(n._selected){delete n._selected;return false}else{n._selected=true;return true}}return false});m.model.set("selectedNode",n);$("#phyloVizSelectedNodeName").val(n.name);$("#phyloVizSelectedNodeDist").val(n.dist);$("#phyloVizSelectedNodeAnnotation").val(n.annotation||"")},addTooltips:function(){$(".bs-tooltip").remove();$(".node").attr("data-original-title",function(){var n=this.__data__,m=n.annotation||"None";return n?(n.name?n.name+"<br/>":"")+"Dist: "+n.dist+" <br/>Annotation: "+m:""}).tooltip({placement:"top",trigger:"hover"})}});var a=d.extend({initialize:function(n){var m=this;m.margins=n.margins;m.layoutMode="Linear";m.stdInit(n);m.layout();m.updateAndRender(m.model.root)},layout:function(){var m=this;m.tree=new g().layoutMode("Linear");m.diagonal=l.svg.diagonal().projection(function(n){return[n.y,n.x]})},renderNodes:function(m){var t=this,u=t.model.get("fontSize")+"px";t.tree.separation(t.model.get("separation")).leafHeight(t.model.get("leafHeight"));var p=500,n=t.tree.separation(t.model.get("separation")).nodes(t.model.root);var o=t.vis.selectAll("g.node").data(n,function(v){return v.name+v.id||(v.id=++t.i)});t.nodes=n;t.duration=p;var q=o.enter().append("svg:g").attr("class","node").on("dblclick",function(){l.event.stopPropagation()}).on("click",function(v){if(l.event.altKey){t.selectNode(v)}else{if(v.children&&v.children.length===0){return}t.model.toggle(v);t.updateAndRender(v)}});q.attr("transform",function(v){return"translate("+m.y0+","+m.x0+")"});q.append("svg:circle").attr("r",0.000001).style("fill",function(v){return v._children?"lightsteelblue":"#fff"});q.append("svg:text").attr("class","nodeLabel").attr("x",function(v){return v.children||v._children?-10:10}).attr("dy",".35em").attr("text-anchor",function(v){return v.children||v._children?"end":"start"}).style("fill-opacity",0.000001);var r=o.transition().duration(p);r.attr("transform",function(v){return"translate("+v.y+","+v.x+")"});r.select("circle").attr("r",t.defaults.nodeRadius).style("fill",function(v){return v._children?"lightsteelblue":"#fff"});r.select("text").style("fill-opacity",1).style("font-size",u).text(function(v){return v.name});var s=o.exit().transition().duration(p).remove();s.select("circle").attr("r",0.000001);s.select("text").style("fill-opacity",0.000001);n.forEach(function(v){v.x0=v.x;v.y0=v.y})}});var i=Backbone.View.extend({className:"phyloviz",initialize:function(n){var m=this;m.MIN_SCALE=0.05;m.MAX_SCALE=5;m.MAX_DISPLACEMENT=500;m.margins=[10,60,10,80];m.width=$("#PhyloViz").width();m.height=$("#PhyloViz").height();m.radius=m.width;m.data=n.data;$(window).resize(function(){m.width=$("#PhyloViz").width();m.height=$("#PhyloViz").height();m.render()});m.phyloTree=new b(n.config);m.phyloTree.root=m.data;m.zoomFunc=l.behavior.zoom().scaleExtent([m.MIN_SCALE,m.MAX_SCALE]);m.zoomFunc.translate(m.phyloTree.get("translate"));m.zoomFunc.scale(m.phyloTree.get("scaleFactor"));m.navMenu=new c(m);m.settingsMenu=new h({phyloTree:m.phyloTree});m.nodeSelectionView=new e({phyloTree:m.phyloTree});m.search=new j();setTimeout(function(){m.zoomAndPan()},1000)},render:function(){var n=this;$("#PhyloViz").empty();n.mainSVG=l.select("#PhyloViz").append("svg:svg").attr("width",n.width).attr("height",n.height).attr("pointer-events","all").call(n.zoomFunc.on("zoom",function(){n.zoomAndPan()}));n.boundingRect=n.mainSVG.append("svg:rect").attr("class","boundingRect").attr("width",n.width).attr("height",n.height).attr("stroke","black").attr("fill","white");n.vis=n.mainSVG.append("svg:g").attr("class","vis");n.layoutOptions={model:n.phyloTree,width:n.width,height:n.height,vis:n.vis,margins:n.margins};$("#title").text("Phylogenetic Tree from "+n.phyloTree.get("title")+":");var m=new a(n.layoutOptions)},zoomAndPan:function(m){var s,o;if(typeof m!=="undefined"){s=m.zoom;o=m.translate}var v=this,q=v.zoomFunc.scale(),u=v.zoomFunc.translate(),r="",t="";switch(s){case"reset":q=1;u=[0,0];break;case"+":q*=1.1;break;case"-":q*=0.9;break;default:if(typeof s==="number"){q=s}else{if(l.event!==null){q=l.event.scale}}}if(q<v.MIN_SCALE||q>v.MAX_SCALE){return}v.zoomFunc.scale(q);r="translate("+v.margins[3]+","+v.margins[0]+") scale("+q+")";if(l.event!==null){t="translate("+l.event.translate+")"}else{if(typeof o!=="undefined"){var p=o.split(",")[0];var n=o.split(",")[1];if(!isNaN(p)&&!isNaN(n)){u=[u[0]+parseFloat(p),u[1]+parseFloat(n)]}}v.zoomFunc.translate(u);t="translate("+u+")"}v.phyloTree.set("scaleFactor",q);v.phyloTree.set("translate",u);v.vis.attr("transform",t+r)},reloadViz:function(){var n=this,p=$("#phylovizNexSelector :selected").val(),m=n.phyloTree.get("dataset_id"),o="phyloviz/getJsonData?dataset_id="+m+"&treeIndex="+String(p);$.getJSON(o,function(q){window.initPhyloViz(q.data,q.config)})}});var c=Backbone.View.extend({initialize:function(n){var m=this;m.phylovizView=n;$("#panelHeaderRightBtns").empty();$("#phyloVizNavBtns").empty();$("#phylovizNexSelector").off();m.initNavBtns();m.initRightHeaderBtns();$("#phylovizNexSelector").off().on("change",function(){m.phylovizView.reloadViz()})},initRightHeaderBtns:function(){var m=this;rightMenu=create_icon_buttons_menu([{icon_class:"gear",title:"PhyloViz Settings",on_click:function(){$("#SettingsMenu").show();m.settingsMenu.updateUI()}},{icon_class:"disk",title:"Save visualization",on_click:function(){var n=$("#phylovizNexSelector option:selected").text();if(n){m.phylovizView.phyloTree.set("title",n)}m.phylovizView.phyloTree.save()}},{icon_class:"chevron-expand",title:"Search / Edit Nodes",on_click:function(){$("#nodeSelectionView").show()}},{icon_class:"information",title:"Phyloviz Help",on_click:function(){window.open("http://wiki.g2.bx.psu.edu/Learn/Visualization/PhylogeneticTree")}}],{tooltip_config:{placement:"bottom"}});$("#panelHeaderRightBtns").append(rightMenu.$el)},initNavBtns:function(){var m=this,n=create_icon_buttons_menu([{icon_class:"zoom-in",title:"Zoom in",on_click:function(){m.phylovizView.zoomAndPan({zoom:"+"})}},{icon_class:"zoom-out",title:"Zoom out",on_click:function(){m.phylovizView.zoomAndPan({zoom:"-"})}},{icon_class:"arrow-circle",title:"Reset Zoom/Pan",on_click:function(){m.phylovizView.zoomAndPan({zoom:"reset"})}}],{tooltip_config:{placement:"bottom"}});$("#phyloVizNavBtns").append(n.$el)}});var h=k.extend({className:"Settings",initialize:function(n){var m=this;m.phyloTree=n.phyloTree;m.el=$("#SettingsMenu");m.inputs={separation:$("#phyloVizTreeSeparation"),leafHeight:$("#phyloVizTreeLeafHeight"),fontSize:$("#phyloVizTreeFontSize")};$("#settingsCloseBtn").off().on("click",function(){m.el.hide()});$("#phylovizResetSettingsBtn").off().on("click",function(){m.resetToDefaults()});$("#phylovizApplySettingsBtn").off().on("click",function(){m.apply()})},apply:function(){var m=this;if(!m.isAcceptableValue(m.inputs.separation,50,2500)||!m.isAcceptableValue(m.inputs.leafHeight,5,30)||!m.isAcceptableValue(m.inputs.fontSize,5,20)){return}$.each(m.inputs,function(n,o){m.phyloTree.set(n,o.val())})},updateUI:function(){var m=this;$.each(m.inputs,function(n,o){o.val(m.phyloTree.get(n))})},resetToDefaults:function(){$(".bs-tooltip").remove();var m=this;$.each(m.phyloTree.defaults,function(n,o){m.phyloTree.set(n,o)});m.updateUI()},render:function(){}});var e=k.extend({className:"Settings",initialize:function(n){var m=this;m.el=$("#nodeSelectionView");m.phyloTree=n.phyloTree;m.UI={enableEdit:$("#phylovizEditNodesCheck"),saveChanges:$("#phylovizNodeSaveChanges"),cancelChanges:$("#phylovizNodeCancelChanges"),name:$("#phyloVizSelectedNodeName"),dist:$("#phyloVizSelectedNodeDist"),annotation:$("#phyloVizSelectedNodeAnnotation")};m.valuesOfConcern={name:null,dist:null,annotation:null};$("#nodeSelCloseBtn").off().on("click",function(){m.el.hide()});m.UI.saveChanges.off().on("click",function(){m.updateNodes()});m.UI.cancelChanges.off().on("click",function(){m.cancelChanges()});(function(o){o.fn.enable=function(p){return o(this).each(function(){if(p){o(this).removeAttr("disabled")}else{o(this).attr("disabled","disabled")}})}})(jQuery);m.UI.enableEdit.off().on("click",function(){m.toggleUI()})},toggleUI:function(){var m=this,n=m.UI.enableEdit.is(":checked");if(!n){m.cancelChanges()}$.each(m.valuesOfConcern,function(o,p){m.UI[o].enable(n)});if(n){m.UI.saveChanges.show();m.UI.cancelChanges.show()}else{m.UI.saveChanges.hide();m.UI.cancelChanges.hide()}},cancelChanges:function(){var m=this,n=m.phyloTree.get("selectedNode");if(n){$.each(m.valuesOfConcern,function(o,p){m.UI[o].val(n[o])})}},updateNodes:function(){var m=this,n=m.phyloTree.get("selectedNode");if(n){if(!m.isAcceptableValue(m.UI.dist,0,1)||m.hasIllegalJsonCharacters(m.UI.name)||m.hasIllegalJsonCharacters(m.UI.annotation)){return}$.each(m.valuesOfConcern,function(o,p){(n[o])=m.UI[o].val()});m.phyloTree.set("nodeAttrChangedTime",new Date())}else{alert("No node selected")}}});var j=k.extend({initialize:function(){var m=this;$("#phyloVizSearchBtn").on("click",function(){var o=$("#phyloVizSearchTerm"),p=$("#phyloVizSearchCondition").val().split("-"),n=p[0],q=p[1];m.hasIllegalJsonCharacters(o);if(n==="dist"){m.isAcceptableValue(o,0,1)}m.searchTree(n,q,o.val())})},searchTree:function(m,o,n){l.selectAll("g.node").classed("searchHighlight",function(q){var p=q[m];if(typeof p!=="undefined"&&p!==null){if(m==="dist"){switch(o){case"greaterEqual":return p>=+n;case"lesserEqual":return p<=+n;default:return}}else{if(m==="name"||m==="annotation"){return p.toLowerCase().indexOf(n.toLowerCase())!==-1}}}})}});return{PhylovizView:i}});
\ No newline at end of file
diff -r 89c27f6b20f8f261a8e45e33abcc2ed9c1509a71 -r f3b183e756f9b209ef0904718ed547e04c74ab7a static/scripts/packed/viz/scatterplot.js
--- a/static/scripts/packed/viz/scatterplot.js
+++ b/static/scripts/packed/viz/scatterplot.js
@@ -1,1 +1,1 @@
-define(["../libs/underscore","../libs/d3","../mvc/base-mvc"],function(){function b(f){var i=this,d=10,h=7,g=10,e=8,c=5;this.log=function(){if(this.debugging&&console&&console.debug){var j=Array.prototype.slice.call(arguments);j.unshift(this.toString());console.debug.apply(null,j)}};this.log("new TwoVarScatterplot:",f);this.defaults={id:"TwoVarScatterplot",containerSelector:"body",maxDataPoints:30000,bubbleRadius:4,entryAnimDuration:500,xNumTicks:10,yNumTicks:10,xAxisLabelBumpY:40,yAxisLabelBumpX:-35,width:500,height:500,marginTop:50,marginRight:50,marginBottom:50,marginLeft:50,xMin:null,xMax:null,yMin:null,yMax:null,xLabel:"X",yLabel:"Y"};this.config=_.extend({},this.defaults,f);this.updateConfig=function(j){_.extend(this.config,j)};this.toString=function(){return this.config.id};this.translateStr=function(j,k){return"translate("+j+","+k+")"};this.rotateStr=function(k,j,l){return"rotate("+k+","+j+","+l+")"};this.svg=d3.select(this.config.containerSelector).append("svg:svg").attr("class","chart").style("display","none");this.content=this.svg.append("svg:g").attr("class","content");this.xAxis=this.content.append("g").attr("class","axis").attr("id","x-axis");this.xAxisLabel=this.xAxis.append("text").attr("class","axis-label").attr("id","x-axis-label");this.yAxis=this.content.append("g").attr("class","axis").attr("id","y-axis");this.yAxisLabel=this.yAxis.append("text").attr("class","axis-label").attr("id","y-axis-label");this.log("built svg:",d3.selectAll("svg"));this.adjustChartDimensions=function(m,k,j,l){m=m||0;k=k||0;j=j||0;l=l||0;this.svg.attr("width",this.config.width+(this.config.marginRight+k)+(this.config.marginLeft+l)).attr("height",this.config.height+(this.config.marginTop+m)+(this.config.marginBottom+j)).style("display","block");this.content=this.svg.select("g.content").attr("transform",this.translateStr(this.config.marginLeft+l,this.config.marginTop+m))};this.preprocessData=function(j){return(j.length>this.config.maxDataPoints)?(j.slice(0,this.config.maxDataPoints)):(j)};this.setUpDomains=function(j,l,k){this.log("setUpDomains");this.xMin=this.config.xMin||(k)?(k[0].min):(d3.min(j));this.xMax=this.config.xMax||(k)?(k[0].max):(d3.max(j));this.yMin=this.config.yMin||(k)?(k[1].min):(d3.min(l));this.yMax=this.config.yMax||(k)?(k[1].max):(d3.max(l))};this.setUpScales=function(){this.xScale=d3.scale.linear().domain([this.xMin,this.xMax]).range([0,this.config.width]),this.yScale=d3.scale.linear().domain([this.yMin,this.yMax]).range([this.config.height,0])};this.setUpXAxis=function(){this.xAxisFn=d3.svg.axis().scale(this.xScale).ticks(this.config.xNumTicks).orient("bottom");this.xAxis.attr("transform",this.translateStr(0,this.config.height)).call(this.xAxisFn);this.xLongestLabel=d3.max(_.map([this.xMin,this.xMax],function(j){return(String(j)).length}));if(this.xLongestLabel>=c){this.xAxis.selectAll("g").filter(":nth-child(odd)").style("display","none")}this.xAxisLabel.attr("x",this.config.width/2).attr("y",this.config.xAxisLabelBumpY).attr("text-anchor","middle").text(this.config.xLabel)};this.setUpYAxis=function(){this.yAxisFn=d3.svg.axis().scale(this.yScale).ticks(this.config.yNumTicks).orient("left");this.yAxis.call(this.yAxisFn);this.log("yAxis:",this.yAxis);var j=this.yAxis.selectAll("text").filter(function(n,m){return m!==0});this.yLongestLabel=d3.max(j[0].map(function(n,m){return(d3.select(n).text()).length}))||0;var k=d+(this.yLongestLabel*h)+e+g;this.config.yAxisLabelBumpX=-(k-g);if(this.config.marginLeft<k){var l=(k)-this.config.marginLeft;l=(l<0)?(0):(l);this.log("adjusting:",l);this.adjustChartDimensions(0,0,0,l)}this.yAxisLabel.attr("x",this.config.yAxisLabelBumpX).attr("y",this.config.height/2).attr("text-anchor","middle").attr("transform",this.rotateStr(-90,this.config.yAxisLabelBumpX,this.config.height/2)).text(this.config.yLabel)};this.renderGrid=function(){this.vGridLines=this.content.selectAll("line.v-grid-line").data(this.xScale.ticks(this.xAxisFn.ticks()[0]));this.vGridLines.enter().append("svg:line").classed("grid-line v-grid-line",true);this.vGridLines.attr("x1",this.xScale).attr("y1",0).attr("x2",this.xScale).attr("y2",this.config.height);this.vGridLines.exit().remove();this.hGridLines=this.content.selectAll("line.h-grid-line").data(this.yScale.ticks(this.yAxisFn.ticks()[0]));this.hGridLines.enter().append("svg:line").classed("grid-line h-grid-line",true);this.hGridLines.attr("x1",0).attr("y1",this.yScale).attr("x2",this.config.width).attr("y2",this.yScale);this.hGridLines.exit().remove()};this.glyphEnterState=function(j){};this.glyphFinalState=function(j){};this.glyphExitState=function(j){};this.renderDatapoints=function(j,m){var l=function(o,n){return i.xScale(j[n])};var k=function(o,n){return i.yScale(m[n])};this.datapoints=this.content.selectAll(".glyph").data(j);this.datapoints.enter().append("svg:circle").attr("class","glyph").attr("cx",l).attr("cy",0).attr("r",0);this.datapoints.transition().duration(this.config.entryAnimDuration).attr("cx",l).attr("cy",k).attr("r",this.config.bubbleRadius);this.datapoints.exit().transition().duration(this.config.entryAnimDuration).attr("cy",this.config.height).attr("r",0).style("fill-opacity",0).remove()};this.render=function(k,l){var j=k[0],m=k[1];this.log("renderScatterplot",j.length,m.length,this.config);j=this.preprocessData(j);m=this.preprocessData(m);this.setUpDomains(j,m,l);this.log("xMin, xMax, yMin, yMax:",this.xMin,this.xMax,this.yMin,this.yMax);this.setUpScales();this.adjustChartDimensions();this.setUpXAxis();this.setUpYAxis();this.renderGrid();this.renderDatapoints(j,m)}}var a=BaseView.extend(LoggableMixin).extend({tagName:"form",className:"scatterplot-settings-form",loadingIndicatorImagePath:(galaxy_paths.get("image_path")+"/loading_large_white_bg.gif"),events:{"click #render-button":"renderScatterplot"},initialize:function(c){if(!c||!c.dataset){throw ("ScatterplotView requires a dataset")}else{this.dataset=c.dataset}this.apiDatasetsURL=c.apiDatasetsURL;this.chartConfig=c.chartConfig||{};this.log("this.chartConfig:",this.chartConfig);this.plot=new b(this.chartConfig)},render:function(){var c=this,e="",d="";this.dataset.metadata_column_types=this.dataset.metadata_column_types.split(", ");_.each(this.dataset.metadata_column_types,function(h,g){if(h==="int"||h==="float"){var f="column "+g;if(c.dataset.metadata_column_names){f=c.dataset.metadata_column_names[g]}d+='<option value="'+g+'">'+f+"</option>"}});e+='<div id="loading-indicator" style="display: none;">';e+='<img class="loading-img" src='+this.loadingIndicatorImagePath+" />";e+='<span class="loading-message"></span>';e+="</div>";e+='<div id="x-column-input">';e+='<label for="">Data column for X: </label><select name="x-column">'+d+"</select>";e+="</div>";e+='<div id="y-column-input">';e+='<label for="">Data column for Y: </label><select name="y-column">'+d+"</select>";e+="</div>";e+='<input id="render-button" type="button" value="Draw" />';e+='<div class="clear"></div>';this.$el.append(e);this.$el.find("#render-button");return this},showLoadingIndicator:function(c){c=c||"";this.$el.find("div#loading-indicator").children(".loading-message").text(c);this.$el.find("div#loading-indicator").show("fast")},hideLoadingIndicator:function(){this.$el.find("div#loading-indicator").hide("fast")},renderScatterplot:function(){var d=this,e=this.apiDatasetsURL+"/"+this.dataset.id+"?data_type=raw_data&",i=this.$el.find('[name="x-column"]'),j=i.val(),g=i.children('[value="'+j+'"]').text(),h=this.$el.find('[name="y-column"]'),f=h.val(),c=h.children('[value="'+f+'"]').text();this.log(g,c);this.chartConfig.xLabel=g;this.chartConfig.yLabel=c;d.plot.updateConfig(this.chartConfig);e+=jQuery.param({columns:"["+[j,f]+"]"});this.log("url:",e);this.showLoadingIndicator("Fetching data...");jQuery.ajax({url:e,dataType:"json",success:function(k){d.showLoadingIndicator("Rendering...");d.endpoint=k.endpoint;d.plot.render(k.data,k.meta);d.hideLoadingIndicator()},error:function(m,k,l){d.hideLoadingIndicator();alert("ERROR:"+k+"\n"+l)}})}});return{ScatterplotView:a}});
\ No newline at end of file
+define(["../libs/underscore","../libs/d3","../mvc/base-mvc","../templates/compiled/template-visualization-scatterplotControlForm"],function(){function a(f){var i=this,d=10,h=7,g=10,e=8,c=5;this.log=function(){if(this.debugging&&console&&console.debug){var j=Array.prototype.slice.call(arguments);j.unshift(this.toString());console.debug.apply(null,j)}};this.log("new TwoVarScatterplot:",f);this.defaults={id:"TwoVarScatterplot",containerSelector:"body",maxDataPoints:30000,bubbleRadius:4,entryAnimDuration:500,xNumTicks:10,yNumTicks:10,xAxisLabelBumpY:40,yAxisLabelBumpX:-35,width:500,height:500,marginTop:50,marginRight:50,marginBottom:50,marginLeft:50,xMin:null,xMax:null,yMin:null,yMax:null,xLabel:"X",yLabel:"Y"};this.config=_.extend({},this.defaults,f);this.updateConfig=function(j){_.extend(this.config,j)};this.toString=function(){return this.config.id};this.translateStr=function(j,k){return"translate("+j+","+k+")"};this.rotateStr=function(k,j,l){return"rotate("+k+","+j+","+l+")"};this.svg=d3.select(this.config.containerSelector).append("svg:svg").attr("class","chart").style("display","none");this.content=this.svg.append("svg:g").attr("class","content");this.xAxis=this.content.append("g").attr("class","axis").attr("id","x-axis");this.xAxisLabel=this.xAxis.append("text").attr("class","axis-label").attr("id","x-axis-label");this.yAxis=this.content.append("g").attr("class","axis").attr("id","y-axis");this.yAxisLabel=this.yAxis.append("text").attr("class","axis-label").attr("id","y-axis-label");this.log("built svg:",d3.selectAll("svg"));this.adjustChartDimensions=function(m,k,j,l){m=m||0;k=k||0;j=j||0;l=l||0;this.svg.attr("width",this.config.width+(this.config.marginRight+k)+(this.config.marginLeft+l)).attr("height",this.config.height+(this.config.marginTop+m)+(this.config.marginBottom+j)).style("display","block");this.content=this.svg.select("g.content").attr("transform",this.translateStr(this.config.marginLeft+l,this.config.marginTop+m))};this.preprocessData=function(j){return(j.length>this.config.maxDataPoints)?(j.slice(0,this.config.maxDataPoints)):(j)};this.setUpDomains=function(j,l,k){this.log("setUpDomains");this.xMin=this.config.xMin||(k)?(k[0].min):(d3.min(j));this.xMax=this.config.xMax||(k)?(k[0].max):(d3.max(j));this.yMin=this.config.yMin||(k)?(k[1].min):(d3.min(l));this.yMax=this.config.yMax||(k)?(k[1].max):(d3.max(l))};this.setUpScales=function(){this.xScale=d3.scale.linear().domain([this.xMin,this.xMax]).range([0,this.config.width]),this.yScale=d3.scale.linear().domain([this.yMin,this.yMax]).range([this.config.height,0])};this.setUpXAxis=function(){this.xAxisFn=d3.svg.axis().scale(this.xScale).ticks(this.config.xNumTicks).orient("bottom");this.xAxis.attr("transform",this.translateStr(0,this.config.height)).call(this.xAxisFn);this.xLongestLabel=d3.max(_.map([this.xMin,this.xMax],function(j){return(String(j)).length}));if(this.xLongestLabel>=c){this.xAxis.selectAll("g").filter(":nth-child(odd)").style("display","none")}this.xAxisLabel.attr("x",this.config.width/2).attr("y",this.config.xAxisLabelBumpY).attr("text-anchor","middle").text(this.config.xLabel)};this.setUpYAxis=function(){this.yAxisFn=d3.svg.axis().scale(this.yScale).ticks(this.config.yNumTicks).orient("left");this.yAxis.call(this.yAxisFn);this.log("yAxis:",this.yAxis);var j=this.yAxis.selectAll("text").filter(function(n,m){return m!==0});this.yLongestLabel=d3.max(j[0].map(function(n,m){return(d3.select(n).text()).length}))||0;var k=d+(this.yLongestLabel*h)+e+g;this.config.yAxisLabelBumpX=-(k-g);if(this.config.marginLeft<k){var l=(k)-this.config.marginLeft;l=(l<0)?(0):(l);this.log("adjusting:",l);this.adjustChartDimensions(0,0,0,l)}this.yAxisLabel.attr("x",this.config.yAxisLabelBumpX).attr("y",this.config.height/2).attr("text-anchor","middle").attr("transform",this.rotateStr(-90,this.config.yAxisLabelBumpX,this.config.height/2)).text(this.config.yLabel)};this.renderGrid=function(){this.vGridLines=this.content.selectAll("line.v-grid-line").data(this.xScale.ticks(this.xAxisFn.ticks()[0]));this.vGridLines.enter().append("svg:line").classed("grid-line v-grid-line",true);this.vGridLines.attr("x1",this.xScale).attr("y1",0).attr("x2",this.xScale).attr("y2",this.config.height);this.vGridLines.exit().remove();this.hGridLines=this.content.selectAll("line.h-grid-line").data(this.yScale.ticks(this.yAxisFn.ticks()[0]));this.hGridLines.enter().append("svg:line").classed("grid-line h-grid-line",true);this.hGridLines.attr("x1",0).attr("y1",this.yScale).attr("x2",this.config.width).attr("y2",this.yScale);this.hGridLines.exit().remove()};this.glyphEnterState=function(j){};this.glyphFinalState=function(j){};this.glyphExitState=function(j){};this.renderDatapoints=function(j,m){var l=function(o,n){return i.xScale(j[n])};var k=function(o,n){return i.yScale(m[n])};this.datapoints=this.content.selectAll(".glyph").data(j);this.datapoints.enter().append("svg:circle").attr("class","glyph").attr("cx",l).attr("cy",0).attr("r",0);this.datapoints.transition().duration(this.config.entryAnimDuration).attr("cx",l).attr("cy",k).attr("r",this.config.bubbleRadius);this.datapoints.exit().transition().duration(this.config.entryAnimDuration).attr("cy",this.config.height).attr("r",0).style("fill-opacity",0).remove()};this.render=function(k,l){var j=k[0],m=k[1];this.log("renderScatterplot",j.length,m.length,this.config);j=this.preprocessData(j);m=this.preprocessData(m);this.setUpDomains(j,m,l);this.log("xMin, xMax, yMin, yMax:",this.xMin,this.xMax,this.yMin,this.yMax);this.setUpScales();this.adjustChartDimensions();this.setUpXAxis();this.setUpYAxis();this.renderGrid();this.renderDatapoints(j,m)}}var b=BaseView.extend(LoggableMixin).extend({tagName:"form",className:"scatterplot-settings-form",loadingIndicatorImagePath:(galaxy_paths.get("image_path")+"/loading_large_white_bg.gif"),events:{"click #render-button":"renderScatterplot"},initialize:function(c){if(!c||!c.dataset){throw ("ScatterplotView requires a dataset")}else{this.dataset=c.dataset}this.apiDatasetsURL=c.apiDatasetsURL;this.chartConfig=c.chartConfig||{};this.log("this.chartConfig:",this.chartConfig);this.plot=new a(this.chartConfig)},render:function(){var c=this,d="";var e={loadingIndicatorImagePath:this.loadingIndicatorImagePath,config:this.chartConfig,availableColumns:[]};_.each(this.dataset.metadata_column_types.split(", "),function(h,g){if(h==="int"||h==="float"){var f="column "+g;if(c.dataset.metadata_column_names){f=c.dataset.metadata_column_names[g]}e.availableColumns.push({index:g,name:f})}});d=b.templates.form(e);this.$el.append(d);return this},showLoadingIndicator:function(c){c=c||"";this.$el.find("div#loading-indicator").children(".loading-message").text(c);this.$el.find("div#loading-indicator").show("fast")},hideLoadingIndicator:function(){this.$el.find("div#loading-indicator").hide("fast")},renderScatterplot:function(){var d=this,e=this.apiDatasetsURL+"/"+this.dataset.id+"?data_type=raw_data&",i=this.$el.find('[name="x-column"]'),j=i.val(),g=i.children('[value="'+j+'"]').text(),h=this.$el.find('[name="y-column"]'),f=h.val(),c=h.children('[value="'+f+'"]').text();this.log(g,c);this.chartConfig.xLabel=g;this.chartConfig.yLabel=c;d.plot.updateConfig(this.chartConfig);e+=jQuery.param({columns:"["+[j,f]+"]"});this.log("url:",e);this.showLoadingIndicator("Fetching data...");jQuery.ajax({url:e,dataType:"json",success:function(k){d.endpoint=k.endpoint;d.showLoadingIndicator("Rendering...");d.plot.render(k.data,k.meta);d.hideLoadingIndicator()},error:function(m,k,l){d.hideLoadingIndicator();alert("ERROR:"+k+"\n"+l)}})}});b.templates=CompiledTemplateLoader.getTemplates({"visualization-templates.html":{form:"template-visualization-scatterplotControlForm"}});return{TwoVarScatterplot:a,ScatterplotControlForm:b}});
\ No newline at end of file
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0

commit/galaxy-central: jgoecks: (a) JSLint cleanup for phyloviz.js and (b) make phyloviz, scatterplot available.
by Bitbucket 04 Oct '12
by Bitbucket 04 Oct '12
04 Oct '12
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/changeset/89c27f6b20f8/
changeset: 89c27f6b20f8
user: jgoecks
date: 2012-10-04 17:07:29
summary: (a) JSLint cleanup for phyloviz.js and (b) make phyloviz, scatterplot available.
affected #: 2 files
diff -r d7eba083859770e676f173b75f2053f575305113 -r 89c27f6b20f8f261a8e45e33abcc2ed9c1509a71 static/scripts/viz/phyloviz.js
--- a/static/scripts/viz/phyloviz.js
+++ b/static/scripts/viz/phyloviz.js
@@ -233,12 +233,16 @@
// removing unnecessary attributes
if (node._selected){ delete node._selected;}
- node.children ? node.children.forEach(cleanTree) : 0;
- node._children ? node._children.forEach(cleanTree) : 0;
+ if (node.children) {
+ node.children.forEach(cleanTree);
+ }
+ if (node._children) {
+ node._children.forEach(cleanTree);
+ }
}
var config = jQuery.extend(true, {}, this.attributes);
- config["selectedNode"] = null;
+ config.selectedNode = null;
show_message("Saving to Galaxy", "progress");
@@ -598,9 +602,11 @@
* Function to zoom and pan the svg element which the entire tree is contained within
* Uses d3.zoom events, and extend them to allow manual updates and keeping states in model
*/
+ var zoomParams,
+ translateParams;
if (typeof event !== "undefined") {
- var zoomParams = event.zoom,
- translateParams = event.translate;
+ zoomParams = event.zoom;
+ translateParams = event.translate;
}
var self = this,
@@ -761,9 +767,9 @@
* Applying user values to phylotree model.
*/
var self = this;
- if (!self.isAcceptableValue(self.inputs["separation"], 50, 2500) ||
- !self.isAcceptableValue(self.inputs["leafHeight"], 5, 30) ||
- !self.isAcceptableValue(self.inputs["fontSize"], 5, 20)){
+ if (!self.isAcceptableValue(self.inputs.separation, 50, 2500) ||
+ !self.isAcceptableValue(self.inputs.leafHeight, 5, 30) ||
+ !self.isAcceptableValue(self.inputs.fontSize, 5, 20)){
return;
}
$.each(self.inputs, function(key, $input){
@@ -854,7 +860,7 @@
var self = this,
checked = self.UI.enableEdit.is(':checked');
- !checked ? self.cancelChanges() : "";
+ if (!checked) { self.cancelChanges(); }
$.each(self.valuesOfConcern, function(key, value) {
self.UI[key].enable(checked);
diff -r d7eba083859770e676f173b75f2053f575305113 -r 89c27f6b20f8f261a8e45e33abcc2ed9c1509a71 templates/root/history_common.mako
--- a/templates/root/history_common.mako
+++ b/templates/root/history_common.mako
@@ -227,10 +227,10 @@
## information--URL base, dataset id, dbkey, visualizations--in anchor.
<%
visualizations = data.get_visualizations()
- ## HACK: if there are visualizations, only provide trackster for now
+ ## HACK: if there are visualizations, only provide a subset for now
## since others are not ready. - comment out to see all WIP visualizations
- #if visualizations:
- # visualizations = [ vis for vis in visualizations if vis in [ 'trackster' ] ]
+ if visualizations:
+ visualizations = [ vis for vis in visualizations if vis in [ 'trackster', 'phyloviz', 'scatterplot' ] ]
%>
%if visualizations:
<a href="${h.url_for( controller='visualization' )}"
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0

commit/galaxy-central: jgoecks: Make Phyloviz into an AMD module and use requireJS for Phyloviz.
by Bitbucket 04 Oct '12
by Bitbucket 04 Oct '12
04 Oct '12
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/changeset/d7eba0838597/
changeset: d7eba0838597
user: jgoecks
date: 2012-10-04 16:51:10
summary: Make Phyloviz into an AMD module and use requireJS for Phyloviz.
affected #: 2 files
diff -r 6f9ce8692bb6aae38d720abd489f8e0edfd5f8c3 -r d7eba083859770e676f173b75f2053f575305113 static/scripts/viz/phyloviz.js
--- a/static/scripts/viz/phyloviz.js
+++ b/static/scripts/viz/phyloviz.js
@@ -1,3 +1,5 @@
+define(['libs/d3', 'viz/visualization'], function(d3, visualization_mod) {
+
var UserMenuBase = Backbone.View.extend({
/**
* Base class of any menus that takes in user interaction. Contains checking methods.
@@ -165,7 +167,7 @@
/**
* -- PhyloTree Model --
*/
-var PhyloTree = Visualization.extend({
+var PhyloTree = visualization_mod.Visualization.extend({
defaults : {
layout: "Linear",
separation : 250, // px dist between nodes of different depth to represent 1 evolutionary until
@@ -588,7 +590,7 @@
$("#title").text("Phylogenetic Tree from " + self.phyloTree.get("title") + ":");
// -- Create Linear view instance --
- var linearView = new PhylovizLinearView(self.layoutOptions)
+ var linearView = new PhylovizLinearView(self.layoutOptions);
},
zoomAndPan : function(event){
@@ -952,4 +954,10 @@
}
});
}
+});
+
+return {
+ PhylovizView: PhylovizView
+};
+
});
\ No newline at end of file
diff -r 6f9ce8692bb6aae38d720abd489f8e0edfd5f8c3 -r d7eba083859770e676f173b75f2053f575305113 templates/visualization/phyloviz.mako
--- a/templates/visualization/phyloviz.mako
+++ b/templates/visualization/phyloviz.mako
@@ -138,7 +138,43 @@
<%def name="javascripts()">
${parent.javascripts()}
- ${h.js( "galaxy.panels", "libs/d3", "mvc/data", "viz/visualization", "viz/phyloviz")}
+ ${h.js( "libs/require" )}
+
+ <script type="text/javascript">
+
+ require.config({
+ baseUrl: "${h.url_for('/static/scripts')}",
+ shim: {
+ "libs/underscore": { exports: "_" },
+ "libs/d3": { exports: "d3" }
+ }
+ });
+
+ require(["viz/phyloviz"], function(phyloviz_mod) {
+
+ function initPhyloViz(data, config) {
+ var phyloviz;
+
+ // -- Initialization code |-->
+ phyloviz = new phyloviz_mod.PhylovizView({
+ data: data,
+ layout : "Linear",
+ config : config
+ });
+
+ // -- Render viz. --
+ phyloviz.render();
+
+ }
+
+ $(function firstVizLoad(){ // calls when viz is loaded for the first time
+ var config = JSON.parse( '${ h.to_json_string( config )}');
+ var data = JSON.parse('${h.to_json_string(data)}');
+ initPhyloViz(data, config);
+ });
+ });
+
+ </script></%def>
@@ -290,31 +326,6 @@
<div id="PhyloViz" ></div>
- <script type="text/javascript">
-
- function initPhyloViz(data, config) {
- var phyloviz;
-
- // -- Initialization code |-->
- phyloviz = new PhylovizView({
- data: data,
- layout : "Linear",
- config : config
- });
-
- // -- Render viz. --
- phyloviz.render();
-
- }
-
- $(function firstVizLoad(){ // calls when viz is loaded for the first time
- var config = JSON.parse( '${ h.to_json_string( config )}');
- var data = JSON.parse('${h.to_json_string(data)}');
- initPhyloViz(data, config);
- });
-
- </script>
-
</%def>
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0

commit/galaxy-central: jgoecks: Server-side refactoring for PhyloViz: move parsers + data providers into data_providers directory and remove phyloviz controller.
by Bitbucket 04 Oct '12
by Bitbucket 04 Oct '12
04 Oct '12
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/changeset/6f9ce8692bb6/
changeset: 6f9ce8692bb6
user: jgoecks
date: 2012-10-04 16:34:57
summary: Server-side refactoring for PhyloViz: move parsers + data providers into data_providers directory and remove phyloviz controller.
affected #: 14 files
diff -r 569f7d07801074a4e5207493afe72354ccb8d3ad -r 6f9ce8692bb6aae38d720abd489f8e0edfd5f8c3 lib/galaxy/visualization/data_providers/phyloviz/__init__.py
--- /dev/null
+++ b/lib/galaxy/visualization/data_providers/phyloviz/__init__.py
@@ -0,0 +1,42 @@
+""" Data providers code for PhyloViz """
+
+from galaxy.visualization.data_providers.basic import BaseDataProvider
+from galaxy.visualization.data_providers.phyloviz.nexusparser import Nexus_Parser
+from galaxy.visualization.data_providers.phyloviz.newickparser import Newick_Parser
+from galaxy.visualization.data_providers.phyloviz.phyloxmlparser import Phyloxml_Parser
+
+class PhylovizDataProvider( BaseDataProvider ):
+
+ def __init__( self, original_dataset=None ):
+ super( PhylovizDataProvider, self ).__init__( original_dataset=original_dataset )
+
+ def get_data( self ):
+ """returns [trees], meta
+ Trees are actually an array of JsonDicts. It's usually one tree, except in the case of Nexus
+ """
+
+ jsonDicts, meta = [], {}
+ file_ext = self.original_dataset.datatype.file_ext
+ file_name = self.original_dataset.file_name
+ try:
+ if file_ext == "nhx": # parses newick files
+ newickParser = Newick_Parser()
+ jsonDicts, parseMsg = newickParser.parseFile( file_name )
+ elif file_ext == "phyloxml": # parses phyloXML files
+ phyloxmlParser = Phyloxml_Parser()
+ jsonDicts, parseMsg = phyloxmlParser.parseFile( file_name )
+ elif file_ext == "nex": # parses nexus files
+ nexusParser = Nexus_Parser()
+ jsonDicts, parseMsg = nexusParser.parseFile( file_name )
+ meta["trees"] = parseMsg
+ else:
+ raise Exception("File type is not supported")
+
+ meta["msg"] = parseMsg
+
+ except Exception, e:
+ raise e
+ jsonDicts, meta["msg"] = [], "Parse failed"
+
+ return jsonDicts, meta
+
diff -r 569f7d07801074a4e5207493afe72354ccb8d3ad -r 6f9ce8692bb6aae38d720abd489f8e0edfd5f8c3 lib/galaxy/visualization/data_providers/phyloviz/baseparser.py
--- /dev/null
+++ b/lib/galaxy/visualization/data_providers/phyloviz/baseparser.py
@@ -0,0 +1,125 @@
+import json
+
+class Node(object):
+ """Node class of PhyloTree, which represents a CLAUDE in a phylogenetic tree"""
+ def __init__(self, nodeName, **kwargs):
+ """Creates a node and adds in the typical annotations"""
+ self.name, self.id = nodeName, kwargs.get("id", 0)
+ self.depth = kwargs.get("depth", 0)
+ self.children = []
+
+ self.isInternal = kwargs.get("isInternal", 0)
+ self.length, self.bootstrap = kwargs.get("length", 0), kwargs.get("bootstrap", None)
+ self.events = kwargs.get("events", "")
+
+ # clean up boot strap values
+ if self.bootstrap == -1:
+ self.bootstrap = None
+
+ def addChildNode(self, child):
+ """Adds a child node to the current node"""
+ if isinstance(child, Node):
+ self.children.append(child)
+ else:
+ self.children += child
+
+
+ def __str__(self):
+ return self.name + " id:" + str(self.id) + ", depth: " + str(self.depth)
+
+
+ def toJson(self):
+ """Converts the data in the node to a dict representation of json"""
+ thisJson = {
+ "name" : self.name,
+ "id" : self.id,
+ "depth" : self.depth,
+ "dist" : self.length
+ }
+ thisJson = self.addChildrenToJson(thisJson)
+ thisJson = self.addMiscToJson(thisJson)
+ return thisJson
+
+ def addChildrenToJson(self, jsonDict):
+ """Needs a special method to addChildren, such that the key does not appear in the Jsondict when the children is empty
+ this requirement is due to the layout algorithm used by d3 layout for hiding subtree """
+ if len(self.children) > 0:
+ children = [ node.toJson() for node in self.children]
+ jsonDict["children"] = children
+ return jsonDict
+
+
+ def addMiscToJson(self, jsonDict):
+ """Adds other misc attributes to json if they are present"""
+ if not self.events == "":
+ jsonDict["events"] = self.events
+ if not self.bootstrap == None:
+ jsonDict["bootstrap"] = self.bootstrap
+ return jsonDict
+
+
+
+class PhyloTree(object):
+ """Standardized python based class to represent the phylogenetic tree parsed from different
+ phylogenetic file formats."""
+
+ def __init__(self):
+ self.root, self.rootAttr = None, {}
+ self.nodes = {}
+ self.title = None
+ self.id = 1
+
+ def addAttributesToRoot(self, attrDict):
+ """Adds attributes to root, but first we put it in a temp store and bind it with root when .toJson is called"""
+ for key, value in attrDict.items():
+ self.rootAttr[key] = value
+
+ def makeNode(self, nodeName, **kwargs):
+ """Called to make a node within PhyloTree, arbitrary kwargs can be passed to annotate nodes
+ Tracks the number of nodes via internally incremented id"""
+ kwargs["id"] = self.id
+ self.id += 1
+ return Node(nodeName, **kwargs)
+
+ def addRoot(self, root):
+ """Creates a root for phyloTree"""
+ assert isinstance(root, Node)
+ root.parent = None
+ self.root = root
+
+ def generateJsonableDict(self):
+ """Changes itself into a dictonary by recurssively calling the tojson on all its nodes. Think of it
+ as a dict in an array of dict in an array of dict and so on..."""
+ jsonTree = ""
+ if self.root:
+ assert isinstance(self.root, Node)
+ jsonTree = self.root.toJson()
+ for key, value in self.rootAttr.items():
+ # transfer temporary stored attr to root
+ jsonTree[key] = value
+ else:
+ raise Exception("Root is not assigned!")
+ return jsonTree
+
+
+
+class Base_Parser(object):
+ """Base parsers contain all the methods to handle phylogeny tree creation and
+ converting the data to json that all parsers should have"""
+
+ def __init__(self):
+ self.phyloTrees = []
+
+ def parseFile(self, filePath):
+ """Base method that all phylogeny file parser should have"""
+ raise Exception("Base method for phylogeny file parsers is not implemented")
+
+ def toJson(self, jsonDict):
+ """Convenience method to get a json string from a python json dict"""
+ return json.dumps(jsonDict)
+
+ def _writeJsonToFile(self, filepath, json):
+ """Writes the file out to the system"""
+ f = open(filepath, "w")
+ f.writelines(json)
+ f.close()
diff -r 569f7d07801074a4e5207493afe72354ccb8d3ad -r 6f9ce8692bb6aae38d720abd489f8e0edfd5f8c3 lib/galaxy/visualization/data_providers/phyloviz/newickparser.py
--- /dev/null
+++ b/lib/galaxy/visualization/data_providers/phyloviz/newickparser.py
@@ -0,0 +1,185 @@
+from baseparser import Base_Parser, PhyloTree
+import re
+
+class Newick_Parser(Base_Parser):
+ """For parsing trees stored in the newick format (.nhx)
+ It is necessarily more complex because this parser is later extended by Nexus for parsing newick as well.."""
+
+
+ def __init__(self):
+ super(Newick_Parser, self).__init__()
+
+
+ def parseFile(self, filePath):
+ """Parses a newick file to obtain the string inside. Returns: jsonableDict"""
+ with open(filePath, "r") as newickFile:
+ newickString = newickFile.read()
+ newickString = newickString.replace("\n", "").replace("\r", "")
+ return [self.parseData(newickString)], "Success"
+
+
+ def parseData(self, newickString):
+ """To be called on a newickString directly to parse it. Returns: jsonableDict"""
+ return self._parseNewickToJson(newickString)
+
+
+ def _parseNewickToJson(self, newickString, treeName=None, nameMap=None):
+ """parses a newick representation of a tree into a PhyloTree data structure,
+ which can be easily converted to json"""
+ self.phyloTree = PhyloTree()
+ newickString = self.cleanNewickString(newickString)
+ if nameMap:
+ newickString = self._mapName(newickString, nameMap)
+
+ self.phyloTree.root = self.parseNode(newickString, 0)
+ if nameMap:
+ self.phyloTree.addAttributesToRoot({"treeName": treeName})
+
+ return self.phyloTree.generateJsonableDict()
+
+
+ def cleanNewickString(self, rawNewick):
+ """removing semi colon, and illegal json characters (\,',") and white spaces"""
+ return re.sub(r'\s|;|\"|\'|\\', '', rawNewick)
+
+
+ def _makeNodesFromString(self, string, depth):
+ """elements separated by comma could be empty"""
+
+ if string.find("(") != -1:
+ raise Exception("Tree is not well form, location: " + string)
+
+ childrenString = string.split(",")
+ childrenNodes = []
+
+ for childString in childrenString:
+ if len(childString) == 0:
+ continue
+ nodeInfo = childString.split(":")
+ name, length, bootstrap = "", None, -1
+ if len(nodeInfo) == 2: # has length info
+ length = nodeInfo[1]
+ # checking for bootstap values
+ name = nodeInfo[0]
+ try: # Nexus may bootstrap in names position
+ name = float(name)
+ if 0<= name <= 1:
+ bootstrap = name
+ elif 1 <= name <= 100:
+ bootstrap = name / 100
+ name = ""
+ except ValueError:
+ name = nodeInfo[0]
+ else:
+ name = nodeInfo[0] # string only contains name
+ node = self.phyloTree.makeNode(name, length=length, depth=depth, bootstrap= bootstrap)
+ childrenNodes += [node]
+ return childrenNodes
+
+
+
+ def _mapName(self, newickString, nameMap):
+ """
+ Necessary to replace names of terms inside nexus representation
+ Also, its here because Mailaud's doesnt deal with id_strings outside of quotes(" ")
+ """
+ newString = ""
+ start = 0
+ end = 0
+
+ for i in xrange(len(newickString)):
+ if newickString[i] == "(" or newickString[i] == ",":
+ if re.match(r"[,(]", newickString[i+1:]):
+ continue
+ else:
+ end = i + 1
+ # i now refers to the starting position of the term to be replaced,
+ # we will next find j which is the ending pos of the term
+ for j in xrange(i+1, len(newickString)):
+ enclosingSymbol = newickString[j] # the immediate symbol after a common or left bracket which denotes the end of a term
+ if enclosingSymbol == ")" or enclosingSymbol == ":" or enclosingSymbol == ",":
+ termToReplace = newickString[end:j]
+
+ newString += newickString[start : end] + nameMap[termToReplace] #+ "'" "'" +
+ start = j
+ break
+
+ newString += newickString[start:]
+ return newString
+
+
+ def parseNode(self, string, depth):
+ """ Recursive method for parsing newick string, works by stripping down the string into substring
+ of newick contained with brackers, which is used to call itself.
+ Eg ... ( A, B, (D, E)C, F, G ) ...
+ We will make the preceeding nodes first A, B, then the internal node C, its children D, E,
+ and finally the succeeding nodes F, G"""
+
+ # Base case where there is only an empty string
+ if string == "":
+ return
+ # Base case there its only an internal claude
+ if string.find("(") == -1:
+ return self._makeNodesFromString(string, depth)
+
+ nodes, children = [], [] # nodes refer to the nodes on this level, children refers to the child of the
+ start = 0
+ lenOfPreceedingInternalNodeString = 0
+ bracketStack = []
+
+ for j in xrange(len(string)):
+ if string[j] == "(": #finding the positions of all the open brackets
+ bracketStack.append(j)
+ continue
+ if string[j] == ")": #finding the positions of all the closed brackets to extract claude
+ i = bracketStack.pop()
+
+ if len(bracketStack) == 0: # is child of current node
+
+ InternalNode = None
+
+ #First flat call to make nodes of the same depth but from the preceeding string.
+ startSubstring = string[start + lenOfPreceedingInternalNodeString: i]
+ preceedingNodes = self._makeNodesFromString(startSubstring, depth)
+ nodes += preceedingNodes
+
+ # Then We will try to see if the substring has any internal nodes first, make it then make nodes preceeding it and succeeding it.
+ if j + 1 < len(string):
+ stringRightOfBracket = string[j+1:] # Eg. '(b:0.4,a:0.3)c:0.3, stringRightOfBracket = c:0.3
+ match = re.search(r"[\)\,\(]", stringRightOfBracket)
+ if match:
+ indexOfNextSymbol = match.start()
+ stringRepOfInternalNode = stringRightOfBracket[:indexOfNextSymbol]
+ internalNodes = self._makeNodesFromString( stringRepOfInternalNode, depth)
+ if len(internalNodes) > 0:
+ InternalNode = internalNodes[0]
+ lenOfPreceedingInternalNodeString = len(stringRepOfInternalNode)
+ else: # sometimes the node can be the last element of a string
+ InternalNode = self._makeNodesFromString(string[j+1:], depth)[0]
+ lenOfPreceedingInternalNodeString = len(string) - j
+ if InternalNode == None: #creating a generic node if it is unnamed
+ InternalNode = self.phyloTree.makeNode( "", depth=depth, isInternal=True ) #"internal-" + str(depth)
+ lenOfPreceedingInternalNodeString = 0
+
+ # recussive call to make the internal claude
+ childSubString = string[ i + 1 : j ]
+ InternalNode.addChildNode(self.parseNode(childSubString, depth + 1))
+
+ nodes.append(InternalNode) # we append the internal node later to preserve order
+
+ start = j + 1
+ continue
+
+ if depth == 0: # if its the root node, we do nothing about it and return
+ return nodes[0]
+
+ # Adding last most set of children
+ endString = string[start:]
+ if string[start-1] == ")": # if the symbol belongs to an internal node which is created previously, then we remove it from the string left to parse
+ match = re.search(r"[\)\,\(]", endString)
+ if match:
+ endOfNodeName = start + match.start() + 1
+ endString = string[endOfNodeName:]
+ nodes += self._makeNodesFromString(endString, depth)
+
+ return nodes
diff -r 569f7d07801074a4e5207493afe72354ccb8d3ad -r 6f9ce8692bb6aae38d720abd489f8e0edfd5f8c3 lib/galaxy/visualization/data_providers/phyloviz/nexusparser.py
--- /dev/null
+++ b/lib/galaxy/visualization/data_providers/phyloviz/nexusparser.py
@@ -0,0 +1,107 @@
+from newickparser import Newick_Parser
+import re
+
+MAX_READLINES = 200000
+
+
+class Nexus_Parser(Newick_Parser):
+
+ def __init__(self):
+ super(Nexus_Parser, self).__init__()
+
+ def parseFile(self, filePath):
+ """passes a file and extracts its Nexus content."""
+ return self.parseNexus(filePath)
+
+
+ def parseNexus(self, filename):
+ """ Nexus data is stored in blocks between a line starting with begin and another line starting with end;
+ Commends inside square brackets are to be ignored,
+ For more information: http://wiki.christophchamp.com/index.php/NEXUS_file_format
+ Nexus can store multiple trees
+ """
+
+ with open( filename, "rt") as nex_file:
+ nexlines = nex_file.readlines()
+
+ rowCount = 0
+ inTreeBlock = False # sentinel to check if we are in a tree block
+ intranslateBlock = False # sentinel to check if we are in the translate region of the tree. Stores synonyms of the labellings
+ self.inCommentBlock = False
+ self.nameMapping = None # stores mapping representation used in nexus format
+ treeNames = []
+
+ for line in nexlines:
+ line = line.replace(";\n", "")
+ lline = line.lower()
+
+ if rowCount > MAX_READLINES or (not nex_file) :
+ break
+ rowCount +=1
+ # We are only interested in the tree block.
+ if "begin" in lline and "tree" in lline and not inTreeBlock:
+ inTreeBlock = True
+ continue
+ if inTreeBlock and "end" in lline[:3]:
+ inTreeBlock, currPhyloTree = False, None
+ continue
+
+ if inTreeBlock:
+
+ if "title" in lline: # Adding title to the tree
+ titleLoc = lline.find("title")
+ title = line[titleLoc + 5:].replace(" ", "")
+
+ continue
+
+ if "translate" in lline:
+ intranslateBlock = True
+ self.nameMapping = {}
+ continue
+
+ if intranslateBlock:
+ mappingLine = self.splitLinebyWhitespaces(line)
+ key, value = mappingLine[1], mappingLine[2].replace(",", "").replace("'","") #replacing illegal json characters
+ self.nameMapping[key] = value
+
+ # Extracting newick Trees
+ if "tree" in lline:
+ intranslateBlock = False
+
+ treeLineCols = self.splitLinebyWhitespaces(line)
+ treeName, newick = treeLineCols[2], treeLineCols[-1]
+
+ if newick == "": # Empty lines can be found in tree blocks
+ continue
+
+ currPhyloTree = self._parseNewickToJson(newick, treeName, nameMap=self.nameMapping)
+
+ self.phyloTrees.append(currPhyloTree)
+ treeIndex = len(self.phyloTrees) - 1
+ treeNames.append( (treeName, treeIndex) ) # appending name of tree, and its index
+ continue
+
+ return self.phyloTrees, treeNames
+
+
+ def splitLinebyWhitespaces(self, line):
+ """replace tabs and write spaces to a single write space, so we can properly split it."""
+ return re.split(r"\s+", line)
+
+
+ def checkComments(self, line):
+ """Check to see if the line/lines is a comment."""
+ if not self.inCommentBlock:
+ if "[" in line:
+ if "]" not in line:
+ self.inCommentBlock = True
+ else:
+ return "Nextline" # need to move on to the nextline after getting out of comment
+ else :
+ if "]" in line:
+ if line.rfind("[") > line.rfind("]"):
+ pass # a comment block is closed but another is open.
+ else:
+ self.inCommentBlock = False
+ return "Nextline" # need to move on to the nextline after getting out of comment
+ return ""
\ No newline at end of file
diff -r 569f7d07801074a4e5207493afe72354ccb8d3ad -r 6f9ce8692bb6aae38d720abd489f8e0edfd5f8c3 lib/galaxy/visualization/data_providers/phyloviz/phyloxmlparser.py
--- /dev/null
+++ b/lib/galaxy/visualization/data_providers/phyloviz/phyloxmlparser.py
@@ -0,0 +1,133 @@
+from baseparser import Base_Parser, PhyloTree, Node
+from xml.etree import ElementTree
+
+class Phyloxml_Parser(Base_Parser):
+ """Parses a phyloxml file into a json file that will be passed to PhyloViz for display"""
+
+ def __init__(self):
+ super(Phyloxml_Parser, self).__init__()
+ self.phyloTree = PhyloTree()
+ self.tagsOfInterest = {
+ "clade": "",
+ "name" : "name",
+ "branch_length" : "length",
+ "confidence" : "bootstrap",
+ "events" : "events"
+ }
+
+ def parseFile(self, filePath):
+ """passes a file and extracts its Phylogeny Tree content."""
+ phyloXmlFile = open(filePath, "r")
+
+ xmlTree = ElementTree.parse(phyloXmlFile)
+ xmlRoot = xmlTree.getroot()[0]
+ self.nameSpaceIndex = xmlRoot.tag.rfind("}") + 1 # used later by the clean tag method to remove the name space in every element.tag
+
+ phyloRoot = None
+ for child in xmlRoot:
+ childTag = self.cleanTag(child.tag)
+ if childTag == "clade":
+ phyloRoot = child
+ elif childTag == "name":
+ self.phyloTree.title = child.text
+
+ self.phyloTree.root = self.parseNode(phyloRoot, 0)
+ jsonDict = self.phyloTree.generateJsonableDict()
+ return [jsonDict], "Success"
+
+
+ def parseNode(self, node, depth):
+ """Parses any node within a phyloxml tree and looks out for claude, which signals the creation of
+ nodes - internal OR leaf"""
+
+ tag = self.cleanTag(node.tag)
+ if not tag == "clade":
+ return None
+ hasInnerClade = False
+
+ # peeking once for parent and once for child to check if the node is internal
+ for child in node:
+ childTag = self.cleanTag(child.tag)
+ if childTag == "clade":
+ hasInnerClade = True
+ break
+
+ if hasInnerClade: # this node is an internal node
+ currentNode = self._makeInternalNode(node, depth= depth)
+ for child in node:
+ child = self.parseNode(child, depth + 1)
+ if isinstance(child, Node):
+ currentNode.addChildNode(child)
+
+ else: # this node is a leaf node
+ currentNode = self._makeLeafNode(node, depth=depth+1)
+
+ return currentNode
+
+
+ def _makeLeafNode(self, leafNode, depth = 0 ):
+ """Makes leaf nodes by calling Phylotree methods"""
+ node = {}
+ for child in leafNode:
+ childTag = self.cleanTag(child.tag)
+ if childTag in self.tagsOfInterest:
+ key = self.tagsOfInterest[childTag] # need to map phyloxml terms to ours
+ node[key] = child.text
+
+ node["depth"] = depth
+ return self.phyloTree.makeNode(self._getNodeName(leafNode), **node)
+
+ def _getNodeName(self, node, depth=-1):
+ """Gets the name of a claude. It handles the case where a taxonomy node is involved"""
+
+ def getTagFromTaxonomyNode(node):
+ """Returns the name of a taxonomy node. A taxonomy node have to be treated differently as the name
+ is embedded one level deeper"""
+ phyloxmlTaxoNames = {
+ "common_name" : "",
+ "scientific_name" : "",
+ "code" : ""
+ }
+ for child in node:
+ childTag = self.cleanTag(child.tag)
+ if childTag in phyloxmlTaxoNames:
+ return child.text
+ return ""
+
+ nodeName = ""
+ for child in node:
+ childTag = self.cleanTag(child.tag)
+ if childTag == "name" :
+ nodeName = child.text
+ break
+ elif childTag == "taxonomy":
+ nodeName = getTagFromTaxonomyNode(child)
+ break
+
+ return nodeName
+
+
+ def _makeInternalNode(self, internalNode, depth=0):
+ """ Makes an internal node from an element object that is guranteed to be a parent node.
+ Gets the value of interests like events and appends it to a custom node object that will be passed to PhyloTree to make nodes
+ """
+ node = {}
+ for child in internalNode:
+ childTag = self.cleanTag(child.tag)
+ if childTag == "clade":
+ continue
+ elif childTag in self.tagsOfInterest:
+ if childTag == "events": # events is nested 1 more level deeper than others
+ key, text = "events", self.cleanTag(child[0].tag)
+ else:
+ key = self.tagsOfInterest[childTag]
+ text = child.text
+ node[key] = text
+
+
+ return self.phyloTree.makeNode(self._getNodeName(internalNode, depth), **node)
+
+
+ def cleanTag(self, tagString):
+ return tagString[self.nameSpaceIndex:]
+
\ No newline at end of file
diff -r 569f7d07801074a4e5207493afe72354ccb8d3ad -r 6f9ce8692bb6aae38d720abd489f8e0edfd5f8c3 lib/galaxy/visualization/phyloviz/__init__.py
--- a/lib/galaxy/visualization/phyloviz/__init__.py
+++ /dev/null
@@ -1,1 +0,0 @@
-__author__ = 'Tomithy'
diff -r 569f7d07801074a4e5207493afe72354ccb8d3ad -r 6f9ce8692bb6aae38d720abd489f8e0edfd5f8c3 lib/galaxy/visualization/phyloviz/baseparser.py
--- a/lib/galaxy/visualization/phyloviz/baseparser.py
+++ /dev/null
@@ -1,125 +0,0 @@
-import json
-
-class Node(object):
- """Node class of PhyloTree, which represents a CLAUDE in a phylogenetic tree"""
- def __init__(self, nodeName, **kwargs):
- """Creates a node and adds in the typical annotations"""
- self.name, self.id = nodeName, kwargs.get("id", 0)
- self.depth = kwargs.get("depth", 0)
- self.children = []
-
- self.isInternal = kwargs.get("isInternal", 0)
- self.length, self.bootstrap = kwargs.get("length", 0), kwargs.get("bootstrap", None)
- self.events = kwargs.get("events", "")
-
- # clean up boot strap values
- if self.bootstrap == -1:
- self.bootstrap = None
-
- def addChildNode(self, child):
- """Adds a child node to the current node"""
- if isinstance(child, Node):
- self.children.append(child)
- else:
- self.children += child
-
-
- def __str__(self):
- return self.name + " id:" + str(self.id) + ", depth: " + str(self.depth)
-
-
- def toJson(self):
- """Converts the data in the node to a dict representation of json"""
- thisJson = {
- "name" : self.name,
- "id" : self.id,
- "depth" : self.depth,
- "dist" : self.length
- }
- thisJson = self.addChildrenToJson(thisJson)
- thisJson = self.addMiscToJson(thisJson)
- return thisJson
-
- def addChildrenToJson(self, jsonDict):
- """Needs a special method to addChildren, such that the key does not appear in the Jsondict when the children is empty
- this requirement is due to the layout algorithm used by d3 layout for hiding subtree """
- if len(self.children) > 0:
- children = [ node.toJson() for node in self.children]
- jsonDict["children"] = children
- return jsonDict
-
-
- def addMiscToJson(self, jsonDict):
- """Adds other misc attributes to json if they are present"""
- if not self.events == "":
- jsonDict["events"] = self.events
- if not self.bootstrap == None:
- jsonDict["bootstrap"] = self.bootstrap
- return jsonDict
-
-
-
-class PhyloTree(object):
- """Standardized python based class to represent the phylogenetic tree parsed from different
- phylogenetic file formats."""
-
- def __init__(self):
- self.root, self.rootAttr = None, {}
- self.nodes = {}
- self.title = None
- self.id = 1
-
- def addAttributesToRoot(self, attrDict):
- """Adds attributes to root, but first we put it in a temp store and bind it with root when .toJson is called"""
- for key, value in attrDict.items():
- self.rootAttr[key] = value
-
- def makeNode(self, nodeName, **kwargs):
- """Called to make a node within PhyloTree, arbitrary kwargs can be passed to annotate nodes
- Tracks the number of nodes via internally incremented id"""
- kwargs["id"] = self.id
- self.id += 1
- return Node(nodeName, **kwargs)
-
- def addRoot(self, root):
- """Creates a root for phyloTree"""
- assert isinstance(root, Node)
- root.parent = None
- self.root = root
-
- def generateJsonableDict(self):
- """Changes itself into a dictonary by recurssively calling the tojson on all its nodes. Think of it
- as a dict in an array of dict in an array of dict and so on..."""
- jsonTree = ""
- if self.root:
- assert isinstance(self.root, Node)
- jsonTree = self.root.toJson()
- for key, value in self.rootAttr.items():
- # transfer temporary stored attr to root
- jsonTree[key] = value
- else:
- raise Exception("Root is not assigned!")
- return jsonTree
-
-
-
-class Base_Parser(object):
- """Base parsers contain all the methods to handle phylogeny tree creation and
- converting the data to json that all parsers should have"""
-
- def __init__(self):
- self.phyloTrees = []
-
- def parseFile(self, filePath):
- """Base method that all phylogeny file parser should have"""
- raise Exception("Base method for phylogeny file parsers is not implemented")
-
- def toJson(self, jsonDict):
- """Convenience method to get a json string from a python json dict"""
- return json.dumps(jsonDict)
-
- def _writeJsonToFile(self, filepath, json):
- """Writes the file out to the system"""
- f = open(filepath, "w")
- f.writelines(json)
- f.close()
diff -r 569f7d07801074a4e5207493afe72354ccb8d3ad -r 6f9ce8692bb6aae38d720abd489f8e0edfd5f8c3 lib/galaxy/visualization/phyloviz/newickparser.py
--- a/lib/galaxy/visualization/phyloviz/newickparser.py
+++ /dev/null
@@ -1,185 +0,0 @@
-from baseparser import Base_Parser, PhyloTree
-import re
-
-class Newick_Parser(Base_Parser):
- """For parsing trees stored in the newick format (.nhx)
- It is necessarily more complex because this parser is later extended by Nexus for parsing newick as well.."""
-
-
- def __init__(self):
- super(Newick_Parser, self).__init__()
-
-
- def parseFile(self, filePath):
- """Parses a newick file to obtain the string inside. Returns: jsonableDict"""
- with open(filePath, "r") as newickFile:
- newickString = newickFile.read()
- newickString = newickString.replace("\n", "").replace("\r", "")
- return [self.parseData(newickString)], "Success"
-
-
- def parseData(self, newickString):
- """To be called on a newickString directly to parse it. Returns: jsonableDict"""
- return self._parseNewickToJson(newickString)
-
-
- def _parseNewickToJson(self, newickString, treeName=None, nameMap=None):
- """parses a newick representation of a tree into a PhyloTree data structure,
- which can be easily converted to json"""
- self.phyloTree = PhyloTree()
- newickString = self.cleanNewickString(newickString)
- if nameMap:
- newickString = self._mapName(newickString, nameMap)
-
- self.phyloTree.root = self.parseNode(newickString, 0)
- if nameMap:
- self.phyloTree.addAttributesToRoot({"treeName": treeName})
-
- return self.phyloTree.generateJsonableDict()
-
-
- def cleanNewickString(self, rawNewick):
- """removing semi colon, and illegal json characters (\,',") and white spaces"""
- return re.sub(r'\s|;|\"|\'|\\', '', rawNewick)
-
-
- def _makeNodesFromString(self, string, depth):
- """elements separated by comma could be empty"""
-
- if string.find("(") != -1:
- raise Exception("Tree is not well form, location: " + string)
-
- childrenString = string.split(",")
- childrenNodes = []
-
- for childString in childrenString:
- if len(childString) == 0:
- continue
- nodeInfo = childString.split(":")
- name, length, bootstrap = "", None, -1
- if len(nodeInfo) == 2: # has length info
- length = nodeInfo[1]
- # checking for bootstap values
- name = nodeInfo[0]
- try: # Nexus may bootstrap in names position
- name = float(name)
- if 0<= name <= 1:
- bootstrap = name
- elif 1 <= name <= 100:
- bootstrap = name / 100
- name = ""
- except ValueError:
- name = nodeInfo[0]
- else:
- name = nodeInfo[0] # string only contains name
- node = self.phyloTree.makeNode(name, length=length, depth=depth, bootstrap= bootstrap)
- childrenNodes += [node]
- return childrenNodes
-
-
-
- def _mapName(self, newickString, nameMap):
- """
- Necessary to replace names of terms inside nexus representation
- Also, its here because Mailaud's doesnt deal with id_strings outside of quotes(" ")
- """
- newString = ""
- start = 0
- end = 0
-
- for i in xrange(len(newickString)):
- if newickString[i] == "(" or newickString[i] == ",":
- if re.match(r"[,(]", newickString[i+1:]):
- continue
- else:
- end = i + 1
- # i now refers to the starting position of the term to be replaced,
- # we will next find j which is the ending pos of the term
- for j in xrange(i+1, len(newickString)):
- enclosingSymbol = newickString[j] # the immediate symbol after a common or left bracket which denotes the end of a term
- if enclosingSymbol == ")" or enclosingSymbol == ":" or enclosingSymbol == ",":
- termToReplace = newickString[end:j]
-
- newString += newickString[start : end] + nameMap[termToReplace] #+ "'" "'" +
- start = j
- break
-
- newString += newickString[start:]
- return newString
-
-
- def parseNode(self, string, depth):
- """ Recursive method for parsing newick string, works by stripping down the string into substring
- of newick contained with brackers, which is used to call itself.
- Eg ... ( A, B, (D, E)C, F, G ) ...
- We will make the preceeding nodes first A, B, then the internal node C, its children D, E,
- and finally the succeeding nodes F, G"""
-
- # Base case where there is only an empty string
- if string == "":
- return
- # Base case there its only an internal claude
- if string.find("(") == -1:
- return self._makeNodesFromString(string, depth)
-
- nodes, children = [], [] # nodes refer to the nodes on this level, children refers to the child of the
- start = 0
- lenOfPreceedingInternalNodeString = 0
- bracketStack = []
-
- for j in xrange(len(string)):
- if string[j] == "(": #finding the positions of all the open brackets
- bracketStack.append(j)
- continue
- if string[j] == ")": #finding the positions of all the closed brackets to extract claude
- i = bracketStack.pop()
-
- if len(bracketStack) == 0: # is child of current node
-
- InternalNode = None
-
- #First flat call to make nodes of the same depth but from the preceeding string.
- startSubstring = string[start + lenOfPreceedingInternalNodeString: i]
- preceedingNodes = self._makeNodesFromString(startSubstring, depth)
- nodes += preceedingNodes
-
- # Then We will try to see if the substring has any internal nodes first, make it then make nodes preceeding it and succeeding it.
- if j + 1 < len(string):
- stringRightOfBracket = string[j+1:] # Eg. '(b:0.4,a:0.3)c:0.3, stringRightOfBracket = c:0.3
- match = re.search(r"[\)\,\(]", stringRightOfBracket)
- if match:
- indexOfNextSymbol = match.start()
- stringRepOfInternalNode = stringRightOfBracket[:indexOfNextSymbol]
- internalNodes = self._makeNodesFromString( stringRepOfInternalNode, depth)
- if len(internalNodes) > 0:
- InternalNode = internalNodes[0]
- lenOfPreceedingInternalNodeString = len(stringRepOfInternalNode)
- else: # sometimes the node can be the last element of a string
- InternalNode = self._makeNodesFromString(string[j+1:], depth)[0]
- lenOfPreceedingInternalNodeString = len(string) - j
- if InternalNode == None: #creating a generic node if it is unnamed
- InternalNode = self.phyloTree.makeNode( "", depth=depth, isInternal=True ) #"internal-" + str(depth)
- lenOfPreceedingInternalNodeString = 0
-
- # recussive call to make the internal claude
- childSubString = string[ i + 1 : j ]
- InternalNode.addChildNode(self.parseNode(childSubString, depth + 1))
-
- nodes.append(InternalNode) # we append the internal node later to preserve order
-
- start = j + 1
- continue
-
- if depth == 0: # if its the root node, we do nothing about it and return
- return nodes[0]
-
- # Adding last most set of children
- endString = string[start:]
- if string[start-1] == ")": # if the symbol belongs to an internal node which is created previously, then we remove it from the string left to parse
- match = re.search(r"[\)\,\(]", endString)
- if match:
- endOfNodeName = start + match.start() + 1
- endString = string[endOfNodeName:]
- nodes += self._makeNodesFromString(endString, depth)
-
- return nodes
diff -r 569f7d07801074a4e5207493afe72354ccb8d3ad -r 6f9ce8692bb6aae38d720abd489f8e0edfd5f8c3 lib/galaxy/visualization/phyloviz/nexusparser.py
--- a/lib/galaxy/visualization/phyloviz/nexusparser.py
+++ /dev/null
@@ -1,107 +0,0 @@
-from newickparser import Newick_Parser
-import re
-
-MAX_READLINES = 200000
-
-
-class Nexus_Parser(Newick_Parser):
-
- def __init__(self):
- super(Nexus_Parser, self).__init__()
-
- def parseFile(self, filePath):
- """passes a file and extracts its Nexus content."""
- return self.parseNexus(filePath)
-
-
- def parseNexus(self, filename):
- """ Nexus data is stored in blocks between a line starting with begin and another line starting with end;
- Commends inside square brackets are to be ignored,
- For more information: http://wiki.christophchamp.com/index.php/NEXUS_file_format
- Nexus can store multiple trees
- """
-
- with open( filename, "rt") as nex_file:
- nexlines = nex_file.readlines()
-
- rowCount = 0
- inTreeBlock = False # sentinel to check if we are in a tree block
- intranslateBlock = False # sentinel to check if we are in the translate region of the tree. Stores synonyms of the labellings
- self.inCommentBlock = False
- self.nameMapping = None # stores mapping representation used in nexus format
- treeNames = []
-
- for line in nexlines:
- line = line.replace(";\n", "")
- lline = line.lower()
-
- if rowCount > MAX_READLINES or (not nex_file) :
- break
- rowCount +=1
- # We are only interested in the tree block.
- if "begin" in lline and "tree" in lline and not inTreeBlock:
- inTreeBlock = True
- continue
- if inTreeBlock and "end" in lline[:3]:
- inTreeBlock, currPhyloTree = False, None
- continue
-
- if inTreeBlock:
-
- if "title" in lline: # Adding title to the tree
- titleLoc = lline.find("title")
- title = line[titleLoc + 5:].replace(" ", "")
-
- continue
-
- if "translate" in lline:
- intranslateBlock = True
- self.nameMapping = {}
- continue
-
- if intranslateBlock:
- mappingLine = self.splitLinebyWhitespaces(line)
- key, value = mappingLine[1], mappingLine[2].replace(",", "").replace("'","") #replacing illegal json characters
- self.nameMapping[key] = value
-
- # Extracting newick Trees
- if "tree" in lline:
- intranslateBlock = False
-
- treeLineCols = self.splitLinebyWhitespaces(line)
- treeName, newick = treeLineCols[2], treeLineCols[-1]
-
- if newick == "": # Empty lines can be found in tree blocks
- continue
-
- currPhyloTree = self._parseNewickToJson(newick, treeName, nameMap=self.nameMapping)
-
- self.phyloTrees.append(currPhyloTree)
- treeIndex = len(self.phyloTrees) - 1
- treeNames.append( (treeName, treeIndex) ) # appending name of tree, and its index
- continue
-
- return self.phyloTrees, treeNames
-
-
- def splitLinebyWhitespaces(self, line):
- """replace tabs and write spaces to a single write space, so we can properly split it."""
- return re.split(r"\s+", line)
-
-
- def checkComments(self, line):
- """Check to see if the line/lines is a comment."""
- if not self.inCommentBlock:
- if "[" in line:
- if "]" not in line:
- self.inCommentBlock = True
- else:
- return "Nextline" # need to move on to the nextline after getting out of comment
- else :
- if "]" in line:
- if line.rfind("[") > line.rfind("]"):
- pass # a comment block is closed but another is open.
- else:
- self.inCommentBlock = False
- return "Nextline" # need to move on to the nextline after getting out of comment
- return ""
\ No newline at end of file
diff -r 569f7d07801074a4e5207493afe72354ccb8d3ad -r 6f9ce8692bb6aae38d720abd489f8e0edfd5f8c3 lib/galaxy/visualization/phyloviz/phyloviz_dataprovider.py
--- a/lib/galaxy/visualization/phyloviz/phyloviz_dataprovider.py
+++ /dev/null
@@ -1,36 +0,0 @@
-from newickparser import Newick_Parser
-from nexusparser import Nexus_Parser
-from phyloxmlparser import Phyloxml_Parser
-from galaxy.visualization.data_providers.basic import BaseDataProvider
-
-class Phyloviz_DataProvider( BaseDataProvider ):
-
- def __init__( self, original_dataset=None ):
- super( BaseDataProvider, self ).__init__( original_dataset=original_dataset )
-
- def get_data( self, **kwargs ):
- """returns [trees], meta
- Trees are actually an array of JsonDicts. It's usually one tree, except in the case of Nexus
- """
- jsonDicts, meta = [], {}
- try:
- if fileExt == "nhx": # parses newick files
- newickParser = Newick_Parser()
- jsonDicts, parseMsg = newickParser.parseFile(filepath)
- elif fileExt == "phyloxml": # parses phyloXML files
- phyloxmlParser = Phyloxml_Parser()
- jsonDicts, parseMsg = phyloxmlParser.parseFile(filepath)
- elif fileExt == "nex": # parses nexus files
- nexusParser = Nexus_Parser()
- jsonDicts, parseMsg = nexusParser.parseFile(filepath)
- meta["trees"] = parseMsg
- else:
- raise Exception("File type is not supported")
-
- meta["msg"] = parseMsg
-
- except Exception:
- jsonDicts, meta["msg"] = [], "Parse failed"
-
- return jsonDicts, meta
-
diff -r 569f7d07801074a4e5207493afe72354ccb8d3ad -r 6f9ce8692bb6aae38d720abd489f8e0edfd5f8c3 lib/galaxy/visualization/phyloviz/phyloxmlparser.py
--- a/lib/galaxy/visualization/phyloviz/phyloxmlparser.py
+++ /dev/null
@@ -1,134 +0,0 @@
-from baseparser import Base_Parser, PhyloTree, Node
-from xml.etree import ElementTree
-
-class Phyloxml_Parser(Base_Parser):
- """Parses a phyloxml file into a json file that will be passed to PhyloViz for display"""
-
- def __init__(self):
- super(Phyloxml_Parser, self).__init__()
- self.phyloTree = PhyloTree()
- self.tagsOfInterest = {
- "clade": "",
- "name" : "name",
- "branch_length" : "length",
- "confidence" : "bootstrap",
- "events" : "events"
- }
-
- def parseFile(self, filePath):
- """passes a file and extracts its Phylogeny Tree content."""
- phyloXmlFile = open(filePath, "r")
-
- xmlTree = ElementTree.parse(phyloXmlFile)
- xmlRoot = xmlTree.getroot()[0]
- self.nameSpaceIndex = xmlRoot.tag.rfind("}") + 1 # used later by the clean tag method to remove the name space in every element.tag
-
- phyloRoot = None
- for child in xmlRoot:
- childTag = self.cleanTag(child.tag)
- if childTag == "clade":
- phyloRoot = child
- elif childTag == "name":
- self.phyloTree.title = child.text
-
- self.phyloTree.root = self.parseNode(phyloRoot, 0)
- jsonDict = self.phyloTree.generateJsonableDict()
- return [jsonDict], "Success"
-
-
- def parseNode(self, node, depth):
- """Parses any node within a phyloxml tree and looks out for claude, which signals the creation of
- nodes - internal OR leaf"""
- assert isinstance(node, etree._Element)
-
- tag = self.cleanTag(node.tag)
- if not tag == "clade":
- return None
- hasInnerClade = False
-
- # peeking once for parent and once for child to check if the node is internal
- for child in node:
- childTag = self.cleanTag(child.tag)
- if childTag == "clade":
- hasInnerClade = True
- break
-
- if hasInnerClade: # this node is an internal node
- currentNode = self._makeInternalNode(node, depth= depth)
- for child in node:
- child = self.parseNode(child, depth + 1)
- if isinstance(child, Node):
- currentNode.addChildNode(child)
-
- else: # this node is a leaf node
- currentNode = self._makeLeafNode(node, depth=depth+1)
-
- return currentNode
-
-
- def _makeLeafNode(self, leafNode, depth = 0 ):
- """Makes leaf nodes by calling Phylotree methods"""
- node = {}
- for child in leafNode:
- childTag = self.cleanTag(child.tag)
- if childTag in self.tagsOfInterest:
- key = self.tagsOfInterest[childTag] # need to map phyloxml terms to ours
- node[key] = child.text
-
- node["depth"] = depth
- return self.phyloTree.makeNode(self._getNodeName(leafNode), **node)
-
- def _getNodeName(self, node, depth=-1):
- """Gets the name of a claude. It handles the case where a taxonomy node is involved"""
-
- def getTagFromTaxonomyNode(node):
- """Returns the name of a taxonomy node. A taxonomy node have to be treated differently as the name
- is embedded one level deeper"""
- phyloxmlTaxoNames = {
- "common_name" : "",
- "scientific_name" : "",
- "code" : ""
- }
- for child in node:
- childTag = self.cleanTag(child.tag)
- if childTag in phyloxmlTaxoNames:
- return child.text
- return ""
-
- nodeName = ""
- for child in node:
- childTag = self.cleanTag(child.tag)
- if childTag == "name" :
- nodeName = child.text
- break
- elif childTag == "taxonomy":
- nodeName = getTagFromTaxonomyNode(child)
- break
-
- return nodeName
-
-
- def _makeInternalNode(self, internalNode, depth=0):
- """ Makes an internal node from an element object that is guranteed to be a parent node.
- Gets the value of interests like events and appends it to a custom node object that will be passed to PhyloTree to make nodes
- """
- node = {}
- for child in internalNode:
- childTag = self.cleanTag(child.tag)
- if childTag == "clade":
- continue
- elif childTag in self.tagsOfInterest:
- if childTag == "events": # events is nested 1 more level deeper than others
- key, text = "events", self.cleanTag(child[0].tag)
- else:
- key = self.tagsOfInterest[childTag]
- text = child.text
- node[key] = text
-
-
- return self.phyloTree.makeNode(self._getNodeName(internalNode, depth), **node)
-
-
- def cleanTag(self, tagString):
- return tagString[self.nameSpaceIndex:]
-
\ No newline at end of file
diff -r 569f7d07801074a4e5207493afe72354ccb8d3ad -r 6f9ce8692bb6aae38d720abd489f8e0edfd5f8c3 lib/galaxy/webapps/galaxy/controllers/phyloviz.py
--- a/lib/galaxy/webapps/galaxy/controllers/phyloviz.py
+++ /dev/null
@@ -1,97 +0,0 @@
-import pkg_resources
-pkg_resources.require( "bx-python" )
-
-from galaxy.util.json import to_json_string, from_json_string
-from galaxy.web.base.controller import *
-from galaxy.visualization.phyloviz.phyloviz_dataprovider import Phyloviz_DataProvider
-
-
-class PhyloVizController( BaseUIController, UsesVisualizationMixin, UsesHistoryDatasetAssociationMixin, SharableMixin ):
- """
- Controller for phyloViz browser interface.
- """
- def __init__(self, app ):
- BaseUIController.__init__( self, app )
-
- @web.expose
- @web.require_login()
- def index( self, trans, dataset_id = None, **kwargs ):
- """
- The index method is called using phyloviz/ with a dataset id passed in.
- The relevant data set is then retrieved via get_json_from_datasetId which interfaces with the parser
- The json representation of the phylogenetic tree along with the config is then written in the .mako template and passed back to the user
- """
- json, config = self.get_json_from_datasetId(trans, dataset_id)
- config["saved_visualization"] = False
- return trans.fill_template( "visualization/phyloviz.mako", data = json, config=config)
-
-
- @web.expose
- def visualization(self, trans, id):
- """
- Called using a viz_id (id) to retrieved stored visualization data (in json format) and all the viz_config
- """
- viz = self.get_visualization(trans, id)
- config = self.get_visualization_config(trans, viz)
- config["saved_visualization"] = True
- data = config["root"]
-
- return trans.fill_template( "visualization/phyloviz.mako", data = data, config=config)
-
-
- @web.expose
- @web.json
- def load_visualization_json(self, trans, viz_id):
- """
- Though not used in current implementation, this provides user with a convenient method to retrieve the viz_data & viz_config via json.
- """
- viz = self.get_visualization(trans, viz_id)
- viz_config = self.get_visualization_config(trans, viz)
- viz_config["saved_visualization"] = True
- return {
- "data" : viz_config["root"],
- "config" : viz_config
- }
-
-
- @web.expose
- @web.json
- def getJsonData(self, trans, dataset_id, treeIndex=0):
- """
- Method to retrieve data asynchronously via json format. Retriving from here rather than
- making a direct datasets/ call allows for some processing and event capturing
- """
- treeIndex = int(treeIndex)
- json, config = self.get_json_from_datasetId(trans, dataset_id, treeIndex)
- packedJson = {
- "data" : json,
- "config" : config
- }
-
- return packedJson
-
-
- def get_json_from_datasetId(self, trans, dataset_id, treeIndex=0):
- """
- For interfacing phyloviz controllers with phyloviz visualization data provider (parsers)
- """
- dataset = self.get_dataset(trans, dataset_id)
- fileExt, filepath = dataset.ext, dataset.file_name # .name stores the name of the dataset from the orginal upload
- json, config = "", {} # config contains properties of the tree and file
-
- if fileExt == "json":
- something, json = self.get_data(dataset)
- else:
- try:
- pd = Phyloviz_DataProvider()
- json, config = pd.get_data(filepath, fileExt)
- json = json[treeIndex]
- except Exception:
- pass
-
- config["title"] = dataset.display_name()
- config["ext"] = fileExt
- config["dataset_id"] = dataset_id
- config["treeIndex"] = treeIndex
-
- return json, config
diff -r 569f7d07801074a4e5207493afe72354ccb8d3ad -r 6f9ce8692bb6aae38d720abd489f8e0edfd5f8c3 lib/galaxy/webapps/galaxy/controllers/visualization.py
--- a/lib/galaxy/webapps/galaxy/controllers/visualization.py
+++ b/lib/galaxy/webapps/galaxy/controllers/visualization.py
@@ -7,7 +7,7 @@
from galaxy.util.sanitize_html import sanitize_html
from galaxy.visualization.genomes import decode_dbkey
from galaxy.visualization.genome.visual_analytics import get_dataset_job
-from galaxy.visualization.data_providers.basic import ColumnDataProvider
+from galaxy.visualization.data_providers.phyloviz import PhylovizDataProvider
from .library import LibraryListGrid
@@ -824,6 +824,25 @@
historyID=history_id,
kwargs=kwargs )
+ @web.expose
+ def phyloviz( self, trans, dataset_id, tree_index=0, **kwargs ):
+ # Get HDA.
+ hda = self.get_dataset( trans, dataset_id, check_ownership=False, check_accessible=True )
+
+ # Get data.
+ pd = PhylovizDataProvider( original_dataset=hda )
+ json, config = pd.get_data()
+ json = json[tree_index]
+
+ config["title"] = hda.display_name()
+ config["ext"] = hda.datatype.file_ext
+ config["dataset_id"] = dataset_id
+ config["treeIndex"] = tree_index
+ config["saved_visualization"] = False
+
+ # Return viz.
+ return trans.fill_template_mako( "visualization/phyloviz.mako", data = json, config=config )
+
@web.json
def bookmarks_from_dataset( self, trans, hda_id=None, ldda_id=None ):
if hda_id:
diff -r 569f7d07801074a4e5207493afe72354ccb8d3ad -r 6f9ce8692bb6aae38d720abd489f8e0edfd5f8c3 templates/root/history_common.mako
--- a/templates/root/history_common.mako
+++ b/templates/root/history_common.mako
@@ -229,8 +229,8 @@
visualizations = data.get_visualizations()
## HACK: if there are visualizations, only provide trackster for now
## since others are not ready. - comment out to see all WIP visualizations
- if visualizations:
- visualizations = [ vis for vis in visualizations if vis in [ 'trackster' ] ]
+ #if visualizations:
+ # visualizations = [ vis for vis in visualizations if vis in [ 'trackster' ] ]
%>
%if visualizations:
<a href="${h.url_for( controller='visualization' )}"
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0

commit/galaxy-central: jgoecks: Refactor PhyloViz components to work in new visualization framework and add sniffers for datatypes.
by Bitbucket 04 Oct '12
by Bitbucket 04 Oct '12
04 Oct '12
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/changeset/569f7d078010/
changeset: 569f7d078010
user: jgoecks
date: 2012-10-04 15:11:04
summary: Refactor PhyloViz components to work in new visualization framework and add sniffers for datatypes.
affected #: 6 files
diff -r e8fc8e57dadc8a1254d994e4e05f40271d7e856b -r 569f7d07801074a4e5207493afe72354ccb8d3ad datatypes_conf.xml.sample
--- a/datatypes_conf.xml.sample
+++ b/datatypes_conf.xml.sample
@@ -252,6 +252,7 @@
<sniffer type="galaxy.datatypes.binary:TwoBit"/><sniffer type="galaxy.datatypes.binary:Bam"/><sniffer type="galaxy.datatypes.binary:Sff"/>
+ <sniffer type="galaxy.datatypes.xml:Phyloxml"/><sniffer type="galaxy.datatypes.xml:GenericXml"/><sniffer type="galaxy.datatypes.sequence:Maf"/><sniffer type="galaxy.datatypes.sequence:Lav"/>
@@ -272,6 +273,8 @@
<sniffer type="galaxy.datatypes.tabular:Pileup"/><sniffer type="galaxy.datatypes.interval:Interval"/><sniffer type="galaxy.datatypes.tabular:Sam"/>
+ <sniffer type="galaxy.datatypes.data:Newick"/>
+ <sniffer type="galaxy.datatypes.data:Nexus"/><sniffer type="galaxy.datatypes.images:Jpg"/><sniffer type="galaxy.datatypes.images:Png"/><sniffer type="galaxy.datatypes.images:Tiff"/>
diff -r e8fc8e57dadc8a1254d994e4e05f40271d7e856b -r 569f7d07801074a4e5207493afe72354ccb8d3ad lib/galaxy/datatypes/data.py
--- a/lib/galaxy/datatypes/data.py
+++ b/lib/galaxy/datatypes/data.py
@@ -734,38 +734,39 @@
"""New Hampshire/Newick Format"""
file_ext = "nhx"
- MetadataElement( name="columns", default=3, desc="Number of columns", readonly=True )
-
def __init__(self, **kwd):
"""Initialize foobar datatype"""
- Text.__init__(self, **kwd)
+ Text.__init__( self, **kwd )
def init_meta( self, dataset, copy_from=None ):
Text.init_meta( self, dataset, copy_from=copy_from )
-
def sniff( self, filename ):
""" Returning false as the newick format is too general and cannot be sniffed."""
return False
+ def get_visualizations( self, dataset ):
+ """
+ Returns a list of visualizations for datatype.
+ """
+
+ return [ 'phyloviz' ]
+
class Nexus( Text ):
"""Nexus format as used By Paup, Mr Bayes, etc"""
file_ext = "nex"
- MetadataElement( name="columns", default=3, desc="Number of columns", readonly=True )
-
def __init__(self, **kwd):
"""Initialize foobar datatype"""
- Text.__init__(self, **kwd)
+ Text.__init__( self, **kwd )
def init_meta( self, dataset, copy_from=None ):
Text.init_meta( self, dataset, copy_from=copy_from )
-
def sniff( self, filename ):
"""All Nexus Files Simply puts a '#NEXUS' in its first line"""
- f = open(filename, "r")
+ f = open( filename, "r" )
firstline = f.readline().upper()
f.close()
@@ -774,6 +775,13 @@
else:
return False
+ def get_visualizations( self, dataset ):
+ """
+ Returns a list of visualizations for datatype.
+ """
+
+ return [ 'phyloviz' ]
+
# ------------- Utility methods --------------
diff -r e8fc8e57dadc8a1254d994e4e05f40271d7e856b -r 569f7d07801074a4e5207493afe72354ccb8d3ad lib/galaxy/datatypes/xml.py
--- a/lib/galaxy/datatypes/xml.py
+++ b/lib/galaxy/datatypes/xml.py
@@ -91,9 +91,18 @@
def sniff( self, filename ):
""""Checking for keyword - 'phyloxml' always in lowercase in the first few lines"""
- f = open(filename, "r")
- firstlines = "".join(f.readlines(5))
+
+ f = open( filename, "r" )
+ firstlines = "".join( f.readlines(5) )
f.close()
+
if "phyloxml" in firstlines:
return True
- return False
\ No newline at end of file
+ return False
+
+ def get_visualizations( self, dataset ):
+ """
+ Returns a list of visualizations for datatype.
+ """
+
+ return [ 'phyloviz' ]
\ No newline at end of file
diff -r e8fc8e57dadc8a1254d994e4e05f40271d7e856b -r 569f7d07801074a4e5207493afe72354ccb8d3ad lib/galaxy/visualization/phyloviz/phyloviz_dataprovider.py
--- a/lib/galaxy/visualization/phyloviz/phyloviz_dataprovider.py
+++ b/lib/galaxy/visualization/phyloviz/phyloviz_dataprovider.py
@@ -3,15 +3,12 @@
from phyloxmlparser import Phyloxml_Parser
from galaxy.visualization.data_providers.basic import BaseDataProvider
-# TODO: bring this class into line with BaseDataProvider by
-# using BaseDataProvider.init() and providing original dataset
-# and then reading from dataset rather than filepath.
class Phyloviz_DataProvider( BaseDataProvider ):
- def __init__( self ):
- pass
+ def __init__( self, original_dataset=None ):
+ super( BaseDataProvider, self ).__init__( original_dataset=original_dataset )
- def get_data( self, filepath, fileExt ):
+ def get_data( self, **kwargs ):
"""returns [trees], meta
Trees are actually an array of JsonDicts. It's usually one tree, except in the case of Nexus
"""
diff -r e8fc8e57dadc8a1254d994e4e05f40271d7e856b -r 569f7d07801074a4e5207493afe72354ccb8d3ad templates/root/history.mako
--- a/templates/root/history.mako
+++ b/templates/root/history.mako
@@ -388,17 +388,6 @@
_.each( $(".visualize-icon"), function(icon) {
init_viz_icon(icon);
});
-
- function init_phyloviz_links() {
- // PhyloViz links
- // Add to trackster browser functionality
- $(".phyloviz-add").live("click", function() {
- var dataset = this,
- dataset_jquery = $(this);
- window.parent.location = dataset_jquery.attr("new-url");
- });
- }
- init_phyloviz_links();
// History rename functionality.
async_save_text("history-name-container", "history-name", "${h.url_for( controller="/history", action="rename_async", id=trans.security.encode_id(history.id) )}", "new_name", 18);
diff -r e8fc8e57dadc8a1254d994e4e05f40271d7e856b -r 569f7d07801074a4e5207493afe72354ccb8d3ad templates/root/history_common.mako
--- a/templates/root/history_common.mako
+++ b/templates/root/history_common.mako
@@ -29,9 +29,6 @@
## Render the dataset `data` as history item, using `hid` as the displayed id
<%def name="render_dataset( data, hid, show_deleted_on_refresh = False, for_editing = True, display_structured = False )"><%
-
- from galaxy.datatypes.xml import Phyloxml
- from galaxy.datatypes.data import Newick, Nexus
dataset_id = trans.security.encode_id( data.id )
if data.state in ['no state','',None]:
@@ -245,14 +242,6 @@
%endif
visualizations="${','.join(visualizations)}"></a>
%endif
- <%
- isPhylogenyData = isinstance(data.datatype, (Phyloxml, Nexus, Newick))
- %>
- %if isPhylogenyData:
- <a href="javascript:void(0)" class="icon-button chart_curve phyloviz-add"
- action-url="${h.url_for( controller='phyloviz', action='-', dataset_id=dataset_id)}"
- new-url="${h.url_for( controller='phyloviz', action='index', dataset_id=dataset_id)}" title="View in Phyloviz"></a>
- %endif
%if trans.user:
%if not display_structured:
<div style="float: right">
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0

commit/galaxy-central: jgoecks: Fix issues with genomes API: handle periods in keys, fix typo, and list genomes when querying.
by Bitbucket 03 Oct '12
by Bitbucket 03 Oct '12
03 Oct '12
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/changeset/e8fc8e57dadc/
changeset: e8fc8e57dadc
user: jgoecks
date: 2012-10-03 23:49:30
summary: Fix issues with genomes API: handle periods in keys, fix typo, and list genomes when querying.
affected #: 2 files
diff -r f78de6cddd0f240aede5f02911379db7102981e2 -r e8fc8e57dadc8a1254d994e4e05f40271d7e856b lib/galaxy/visualization/genomes.py
--- a/lib/galaxy/visualization/genomes.py
+++ b/lib/galaxy/visualization/genomes.py
@@ -236,7 +236,7 @@
if not len_ds:
genome = self.genomes[ dbkey ]
else:
- gneome = Genome( dbkey, len_file=len_ds.file_name )
+ genome = Genome( dbkey, len_file=len_ds.file_name )
return genome.to_dict( num=num, chrom=chrom, low=low )
diff -r f78de6cddd0f240aede5f02911379db7102981e2 -r e8fc8e57dadc8a1254d994e4e05f40271d7e856b lib/galaxy/webapps/galaxy/api/genomes.py
--- a/lib/galaxy/webapps/galaxy/api/genomes.py
+++ b/lib/galaxy/webapps/galaxy/api/genomes.py
@@ -5,6 +5,12 @@
def is_true ( a_str ):
return is_true == True or a_str in [ 'True', 'true', 'T', 't' ]
+def get_id( base, format ):
+ if format:
+ return "%s.%s" % ( base, format )
+ else:
+ return base
+
class GenomesController( BaseAPIController ):
"""
RESTful controller for interactions with genome data.
@@ -16,7 +22,7 @@
GET /api/genomes: returns a list of installed genomes
"""
- return []
+ return self.app.genomes.get_dbkeys_with_chrom_info( trans )
@web.json
def show( self, trans, id, num=None, chrom=None, low=None, high=None, **kwd ):
@@ -27,6 +33,7 @@
"""
# Process kwds.
+ id = get_id( id, kwd.get( 'format', None ) )
reference = is_true( kwd.get( 'reference', False ) )
# Return info.
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0

commit/galaxy-central: smcmanus: Added tool exit code to the UI. Modified stdout, stderr, and exit_code retrieval to reference same method.
by Bitbucket 03 Oct '12
by Bitbucket 03 Oct '12
03 Oct '12
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/changeset/f78de6cddd0f/
changeset: f78de6cddd0f
user: smcmanus
date: 2012-10-03 23:07:40
summary: Added tool exit code to the UI. Modified stdout, stderr, and exit_code retrieval to reference same method.
affected #: 2 files
diff -r e4e1c621b025b4f0b09846e9d4410d2630394470 -r f78de6cddd0f240aede5f02911379db7102981e2 lib/galaxy/webapps/galaxy/controllers/dataset.py
--- a/lib/galaxy/webapps/galaxy/controllers/dataset.py
+++ b/lib/galaxy/webapps/galaxy/controllers/dataset.py
@@ -154,12 +154,24 @@
stored_list_grid = HistoryDatasetAssociationListGrid()
+ def _get_job_for_dataset( self, trans, dataset_id ):
+ '''
+ Return the job for the given dataset. This will throw an error if the
+ dataset is either nonexistent or inaccessible to the user. This looks
+ up the job by mapping the dataset to an HDA and then mapping the HDA
+ to its job. This will throw exceptions so that the caller can determine
+ the appropriate response.
+ '''
+ hda = trans.sa_session.query( trans.app.model.HistoryDatasetAssociation ).get( trans.security.decode_id( dataset_id ) )
+ assert hda and trans.app.security_agent.can_access_dataset( trans.get_current_user_roles(), hda.dataset )
+ return hda.creating_job_associations[0].job
+
@web.expose
def errors( self, trans, id ):
hda = trans.sa_session.query( model.HistoryDatasetAssociation ).get( id )
return trans.fill_template( "dataset/errors.mako", hda=hda )
@web.expose
- def stdout( self, trans, dataset_id=None, **kwargs ):
+ def stdoutX( self, trans, dataset_id=None, **kwargs ):
trans.response.set_content_type( 'text/plain' )
try:
hda = trans.sa_session.query( trans.app.model.HistoryDatasetAssociation ).get( trans.security.decode_id( dataset_id ) )
@@ -168,16 +180,40 @@
except:
return "Invalid dataset ID or you are not allowed to access this dataset"
return job.stdout
+
@web.expose
+ def stdout( self, trans, dataset_id=None, **kwargs ):
+ trans.response.set_content_type( 'text/plain' )
+ stdout = ""
+ try:
+ job = self._get_job_for_dataset( trans, dataset_id )
+ stdout = job.stdout
+ except:
+ stdout = "Invalid dataset ID or you are not allowed to access this dataset"
+ return stdout
+
+ @web.expose
+ # TODO: Migrate stderr and stdout to use _get_job_for_dataset; it wasn't tested.
def stderr( self, trans, dataset_id=None, **kwargs ):
trans.response.set_content_type( 'text/plain' )
+ stderr = ""
try:
- hda = trans.sa_session.query( trans.app.model.HistoryDatasetAssociation ).get( trans.security.decode_id( dataset_id ) )
- assert hda and trans.app.security_agent.can_access_dataset( trans.get_current_user_roles(), hda.dataset )
- job = hda.creating_job_associations[0].job
+ job = self._get_job_for_dataset( trans, dataset_id )
+ stderr = job.stderr
except:
- return "Invalid dataset ID or you are not allowed to access this dataset"
- return job.stderr
+ stderr = "Invalid dataset ID or you are not allowed to access this dataset"
+ return stderr
+
+ @web.expose
+ def exit_code( self, trans, dataset_id=None, **kwargs ):
+ trans.response.set_content_type( 'text/plain' )
+ exit_code = ""
+ try:
+ job = _get_job_for_dataset( dataset_id )
+ exit_code = job.exit_code
+ except:
+ exit_code = "Invalid dataset ID or you are not allowed to access this dataset"
+ return exit_code
@web.expose
def report_error( self, trans, id, email='', message="" ):
smtp_server = trans.app.config.smtp_server
@@ -986,7 +1022,7 @@
pass
inherit_chain = source_dataset_chain(hda, [])
- return trans.fill_template( "show_params.mako", inherit_chain=inherit_chain, history=trans.get_history(), hda=hda, tool=tool, params_objects=params_objects )
+ return trans.fill_template( "show_params.mako", inherit_chain=inherit_chain, history=trans.get_history(), hda=hda, job=job, tool=tool, params_objects=params_objects )
@web.expose
def copy_datasets( self, trans, source_history=None, source_dataset_ids="", target_history_id=None, target_history_ids="", new_history_name="", do_copy=False, **kwd ):
diff -r e4e1c621b025b4f0b09846e9d4410d2630394470 -r f78de6cddd0f240aede5f02911379db7102981e2 templates/show_params.mako
--- a/templates/show_params.mako
+++ b/templates/show_params.mako
@@ -60,6 +60,7 @@
<tr><td>Tool Version:</td><td>${hda.tool_version}</td></tr><tr><td>Tool Standard Output:</td><td><a href="${h.url_for( controller='dataset', action='stdout')}">stdout</a></td></tr><tr><td>Tool Standard Error:</td><td><a href="${h.url_for( controller='dataset', action='stderr')}">stderr</a></td></tr>
+ <tr><td>Tool Exit Code:</td><td>${job.exit_code}</td></tr>
%if trans.user_is_admin() or trans.app.config.expose_dataset_path:
<tr><td>Full Path:</td><td>${hda.file_name}</td></tr>
%endif
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0