galaxy-commits
Threads by month
- ----- 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
August 2012
- 1 participants
- 118 discussions
commit/galaxy-central: natefoo: Don't attempt to run util.umask_fix_perms() on data that is being linked to. Fixes #801.
by Bitbucket 28 Aug '12
by Bitbucket 28 Aug '12
28 Aug '12
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/changeset/483cbfc5341a/
changeset: 483cbfc5341a
user: natefoo
date: 2012-08-28 19:50:54
summary: Don't attempt to run util.umask_fix_perms() on data that is being linked to. Fixes #801.
affected #: 1 file
diff -r d8bff94d8aac276ff77b65104c958ab5cc9ee243 -r 483cbfc5341a0331cc86185f8821cdecec52a0b4 lib/galaxy/jobs/__init__.py
--- a/lib/galaxy/jobs/__init__.py
+++ b/lib/galaxy/jobs/__init__.py
@@ -471,7 +471,7 @@
job.user.total_disk_usage += bytes
# fix permissions
- for path in [ dp.real_path for dp in self.get_output_fnames() ]:
+ for path in [ dp.real_path for dp in self.get_mutable_output_fnames() ]:
util.umask_fix_perms( path, self.app.config.umask, 0666, self.app.config.gid )
self.sa_session.flush()
log.debug( 'job %d ended' % self.job_id )
@@ -679,6 +679,11 @@
self.compute_outputs()
return self.output_paths
+ def get_mutable_output_fnames( self ):
+ if self.output_paths is None:
+ self.compute_outputs()
+ return filter( lambda dsp: dsp.mutable, self.output_paths )
+
def get_output_hdas_and_fnames( self ):
if self.output_hdas_and_paths is None:
self.compute_outputs()
@@ -686,10 +691,11 @@
def compute_outputs( self ) :
class DatasetPath( object ):
- def __init__( self, dataset_id, real_path, false_path = None ):
+ def __init__( self, dataset_id, real_path, false_path = None, mutable = True ):
self.dataset_id = dataset_id
self.real_path = real_path
self.false_path = false_path
+ self.mutable = mutable
def __str__( self ):
if self.false_path is None:
return self.real_path
@@ -706,13 +712,13 @@
self.output_hdas_and_paths = {}
for name, hda in [ ( da.name, da.dataset ) for da in job.output_datasets + job.output_library_datasets ]:
false_path = os.path.abspath( os.path.join( self.working_directory, "galaxy_dataset_%d.dat" % hda.dataset.id ) )
- dsp = DatasetPath( hda.dataset.id, hda.dataset.file_name, false_path )
+ dsp = DatasetPath( hda.dataset.id, hda.dataset.file_name, false_path, mutable = hda.dataset.external_filename is None )
self.output_paths.append( dsp )
self.output_hdas_and_paths[name] = hda, dsp
if special:
false_path = os.path.abspath( os.path.join( self.working_directory, "galaxy_dataset_%d.dat" % special.dataset.id ) )
else:
- results = [ ( da.name, da.dataset, DatasetPath( da.dataset.dataset.id, da.dataset.file_name ) ) for da in job.output_datasets + job.output_library_datasets ]
+ results = [ ( da.name, da.dataset, DatasetPath( da.dataset.dataset.id, da.dataset.file_name, mutable = da.dataset.dataset.external_filename is None ) ) for da in job.output_datasets + job.output_library_datasets ]
self.output_paths = [t[2] for t in results]
self.output_hdas_and_paths = dict([(t[0], t[1:]) for t in results])
if special:
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: greg: Apply the improvements for generation of tool shed URLs to the repository controller.
by Bitbucket 28 Aug '12
by Bitbucket 28 Aug '12
28 Aug '12
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/changeset/d8bff94d8aac/
changeset: d8bff94d8aac
user: greg
date: 2012-08-28 17:49:43
summary: Apply the improvements for generation of tool shed URLs to the repository controller.
affected #: 2 files
diff -r 4b05f621540cb46fd8b120997258008b37050f63 -r d8bff94d8aac276ff77b65104c958ab5cc9ee243 lib/galaxy/web/controllers/admin_toolshed.py
--- a/lib/galaxy/web/controllers/admin_toolshed.py
+++ b/lib/galaxy/web/controllers/admin_toolshed.py
@@ -392,8 +392,9 @@
# Send a request to the relevant tool shed to see if there are any updates.
repository = get_repository( trans, kwd[ 'id' ] )
tool_shed_url = get_url_from_repository_tool_shed( trans.app, repository )
- url = url_join( tool_shed_url, 'repository/check_for_updates?galaxy_url=%s&name=%s&owner=%s&changeset_revision=%s&webapp=galaxy' % \
- ( url_for( '/', qualified=True ), repository.name, repository.owner, repository.changeset_revision ) )
+ url = url_join( tool_shed_url,
+ 'repository/check_for_updates?galaxy_url=%s&name=%s&owner=%s&changeset_revision=%s&webapp=galaxy' % \
+ ( url_for( '/', qualified=True ), repository.name, repository.owner, repository.changeset_revision ) )
return trans.response.send_redirect( url )
@web.expose
@web.require_admin
@@ -634,8 +635,9 @@
tool_shed_repository,
trans.model.ToolShedRepository.installation_status.SETTING_TOOL_VERSIONS )
tool_shed_url = get_url_from_repository_tool_shed( trans.app, tool_shed_repository )
- url = url_join( tool_shed_url, '/repository/get_tool_versions?name=%s&owner=%s&changeset_revision=%s&webapp=galaxy' % \
- ( tool_shed_repository.name, tool_shed_repository.owner, tool_shed_repository.changeset_revision ) )
+ url = url_join( tool_shed_url,
+ '/repository/get_tool_versions?name=%s&owner=%s&changeset_revision=%s&webapp=galaxy' % \
+ ( tool_shed_repository.name, tool_shed_repository.owner, tool_shed_repository.changeset_revision ) )
response = urllib2.urlopen( url )
text = response.read()
response.close()
@@ -954,7 +956,9 @@
repository_ids = kwd.get( 'repository_ids', None )
changeset_revisions = kwd.get( 'changeset_revisions', None )
# Get the information necessary to install each repository.
- url = url_join( tool_shed_url, 'repository/get_repository_information?repository_ids=%s&changeset_revisions=%s&webapp=galaxy' % ( repository_ids, changeset_revisions ) )
+ url = url_join( tool_shed_url,
+ 'repository/get_repository_information?repository_ids=%s&changeset_revisions=%s&webapp=galaxy' % \
+ ( repository_ids, changeset_revisions ) )
response = urllib2.urlopen( url )
raw_text = response.read()
response.close()
@@ -1097,8 +1101,9 @@
name = repo_info_dict.keys()[ 0 ]
repo_info_tuple = repo_info_dict[ name ]
description, repository_clone_url, changeset_revision, ctx_rev, repository_owner, tool_dependencies = repo_info_tuple
- url = url_join( tool_shed_url, 'repository/get_readme?name=%s&owner=%s&changeset_revision=%s&webapp=galaxy' % \
- ( name, repository_owner, changeset_revision ) )
+ url = url_join( tool_shed_url,
+ 'repository/get_readme?name=%s&owner=%s&changeset_revision=%s&webapp=galaxy' % \
+ ( name, repository_owner, changeset_revision ) )
response = urllib2.urlopen( url )
raw_text = response.read()
response.close()
@@ -1273,8 +1278,9 @@
tool_shed = get_tool_shed_from_clone_url( repository_clone_url )
# Get all previous change set revisions from the tool shed for the repository back to, but excluding, the previous valid changeset
# revision to see if it was previously installed using one of them.
- url = url_join( tool_shed_url, 'repository/previous_changeset_revisions?galaxy_url=%s&name=%s&owner=%s&changeset_revision=%s&webapp=galaxy' % \
- ( url_for( '/', qualified=True ), repository_name, repository_owner, changeset_revision ) )
+ url = url_join( tool_shed_url,
+ 'repository/previous_changeset_revisions?galaxy_url=%s&name=%s&owner=%s&changeset_revision=%s&webapp=galaxy' % \
+ ( url_for( '/', qualified=True ), repository_name, repository_owner, changeset_revision ) )
response = urllib2.urlopen( url )
text = response.read()
response.close()
@@ -1350,8 +1356,9 @@
# Get the tool_versions from the tool shed for each tool in the installed change set.
repository = get_repository( trans, kwd[ 'id' ] )
tool_shed_url = get_url_from_repository_tool_shed( trans.app, repository )
- url = url_join( tool_shed_url, 'repository/get_tool_versions?name=%s&owner=%s&changeset_revision=%s&webapp=galaxy' % \
- ( repository.name, repository.owner, repository.changeset_revision ) )
+ url = url_join( tool_shed_url,
+ 'repository/get_tool_versions?name=%s&owner=%s&changeset_revision=%s&webapp=galaxy' % \
+ ( repository.name, repository.owner, repository.changeset_revision ) )
response = urllib2.urlopen( url )
text = response.read()
response.close()
diff -r 4b05f621540cb46fd8b120997258008b37050f63 -r d8bff94d8aac276ff77b65104c958ab5cc9ee243 lib/galaxy/webapps/community/controllers/repository.py
--- a/lib/galaxy/webapps/community/controllers/repository.py
+++ b/lib/galaxy/webapps/community/controllers/repository.py
@@ -11,7 +11,7 @@
from galaxy.model.orm import *
from galaxy.util.shed_util import create_repo_info_dict, get_changectx_for_changeset, get_configured_ui, get_repository_file_contents, NOT_TOOL_CONFIGS
from galaxy.util.shed_util import open_repository_files_folder, reversed_lower_upper_bounded_changelog, reversed_upper_bounded_changelog, strip_path
-from galaxy.util.shed_util import to_html_escaped, update_repository
+from galaxy.util.shed_util import to_html_escaped, update_repository, url_join
from galaxy.tool_shed.encoding_util import *
from common import *
@@ -749,9 +749,10 @@
update = 'true'
no_update = 'false'
else:
- # Start building up the url to redirect back to the calling Galaxy instance.
- url = '%sadmin_toolshed/update_to_changeset_revision?tool_shed_url=%s' % ( galaxy_url, url_for( '/', qualified=True ) )
- url += '&name=%s&owner=%s&changeset_revision=%s&latest_changeset_revision=' % ( repository.name, repository.user.username, changeset_revision )
+ # Start building up the url to redirect back to the calling Galaxy instance.
+ url = url_join( galaxy_url,
+ 'admin_toolshed/update_to_changeset_revision?tool_shed_url=%s&name=%s&owner=%s&changeset_revision=%s&latest_changeset_revision=' % \
+ ( url_for( '/', qualified=True ), repository.name, repository.user.username, changeset_revision ) )
if changeset_revision == repository.tip:
# If changeset_revision is the repository tip, there are no additional updates.
if from_update_manager:
@@ -1395,10 +1396,9 @@
"""Send the list of repository_ids and changeset_revisions to Galaxy so it can begin the installation process."""
galaxy_url = trans.get_cookie( name='toolshedgalaxyurl' )
# Redirect back to local Galaxy to perform install.
- url = '%sadmin_toolshed/prepare_for_install' % galaxy_url
- url += '?tool_shed_url=%s' % url_for( '/', qualified=True )
- url += '&repository_ids=%s' % ','.join( util.listify( repository_ids ) )
- url += '&changeset_revisions=%s' % ','.join( util.listify( changeset_revisions ) )
+ url = url_join( galaxy_url,
+ 'admin_toolshed/prepare_for_install?tool_shed_url=%s&repository_ids=%s&changeset_revisions=%s' % \
+ ( url_for( '/', qualified=True ), ','.join( util.listify( repository_ids ) ), ','.join( util.listify( changeset_revisions ) ) ) )
return trans.response.send_redirect( url )
@web.expose
def load_invalid_tool( self, trans, repository_id, tool_config, changeset_revision, **kwd ):
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
28 Aug '12
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/changeset/4b05f621540c/
changeset: 4b05f621540c
user: inithello
date: 2012-08-28 17:32:17
summary: Improved generation of tool shed URLs
affected #: 2 files
diff -r c87370c5340d359d72301234a958c138adfecd7e -r 4b05f621540cb46fd8b120997258008b37050f63 lib/galaxy/util/shed_util.py
--- a/lib/galaxy/util/shed_util.py
+++ b/lib/galaxy/util/shed_util.py
@@ -454,7 +454,7 @@
def generate_clone_url( trans, repository ):
"""Generate the URL for cloning a repository."""
tool_shed_url = get_url_from_repository_tool_shed( trans.app, repository )
- return '%s/repos/%s/%s' % ( tool_shed_url, repository.owner, repository.name )
+ return url_join( tool_shed_url, 'repos', repository.owner, repository.name )
def generate_datatypes_metadata( datatypes_config, metadata_dict ):
"""Update the received metadata_dict with information from the parsed datatypes_config."""
tree = ElementTree.parse( datatypes_config )
@@ -993,7 +993,7 @@
break
return converter_path, display_path
def get_ctx_rev( tool_shed_url, name, owner, changeset_revision ):
- url = '%s/repository/get_ctx_rev?name=%s&owner=%s&changeset_revision=%s&webapp=galaxy' % ( tool_shed_url, name, owner, changeset_revision )
+ url = url_join( tool_shed_url, 'repository/get_ctx_rev?name=%s&owner=%s&changeset_revision=%s&webapp=galaxy' % ( name, owner, changeset_revision ) )
response = urllib2.urlopen( url )
ctx_rev = response.read()
response.close()
@@ -1221,8 +1221,8 @@
def get_update_to_changeset_revision_and_ctx_rev( trans, repository ):
"""Return the changeset revision hash to which the repository can be updated."""
tool_shed_url = get_url_from_repository_tool_shed( trans.app, repository )
- url = '%s/repository/get_changeset_revision_and_ctx_rev?name=%s&owner=%s&changeset_revision=%s' % \
- ( tool_shed_url, repository.name, repository.owner, repository.installed_changeset_revision )
+ url = url_join( tool_shed_url, 'repository/get_changeset_revision_and_ctx_rev?name=%s&owner=%s&changeset_revision=%s' % \
+ ( repository.name, repository.owner, repository.installed_changeset_revision ) )
try:
response = urllib2.urlopen( url )
encoded_update_dict = response.read()
@@ -1645,3 +1645,8 @@
tool_shed_repository.status = status
sa_session.add( tool_shed_repository )
sa_session.flush()
+def url_join( *args ):
+ parts = []
+ for arg in args:
+ parts.append( arg.strip( '/' ) )
+ return '/'.join( parts )
diff -r c87370c5340d359d72301234a958c138adfecd7e -r 4b05f621540cb46fd8b120997258008b37050f63 lib/galaxy/web/controllers/admin_toolshed.py
--- a/lib/galaxy/web/controllers/admin_toolshed.py
+++ b/lib/galaxy/web/controllers/admin_toolshed.py
@@ -374,7 +374,7 @@
def browse_tool_shed( self, trans, **kwd ):
tool_shed_url = kwd[ 'tool_shed_url' ]
galaxy_url = url_for( '/', qualified=True )
- url = '%srepository/browse_valid_categories?galaxy_url=%s&webapp=galaxy' % ( tool_shed_url, galaxy_url )
+ url = url_join( tool_shed_url, 'repository/browse_valid_categories?galaxy_url=%s&webapp=galaxy' % ( galaxy_url ) )
return trans.response.send_redirect( url )
@web.expose
@web.require_admin
@@ -392,8 +392,8 @@
# Send a request to the relevant tool shed to see if there are any updates.
repository = get_repository( trans, kwd[ 'id' ] )
tool_shed_url = get_url_from_repository_tool_shed( trans.app, repository )
- url = '%s/repository/check_for_updates?galaxy_url=%s&name=%s&owner=%s&changeset_revision=%s&webapp=galaxy' % \
- ( tool_shed_url, url_for( '/', qualified=True ), repository.name, repository.owner, repository.changeset_revision )
+ url = url_join( tool_shed_url, 'repository/check_for_updates?galaxy_url=%s&name=%s&owner=%s&changeset_revision=%s&webapp=galaxy' % \
+ ( url_for( '/', qualified=True ), repository.name, repository.owner, repository.changeset_revision ) )
return trans.response.send_redirect( url )
@web.expose
@web.require_admin
@@ -467,14 +467,14 @@
def find_tools_in_tool_shed( self, trans, **kwd ):
tool_shed_url = kwd[ 'tool_shed_url' ]
galaxy_url = url_for( '/', qualified=True )
- url = '%srepository/find_tools?galaxy_url=%s&webapp=galaxy' % ( tool_shed_url, galaxy_url )
+ url = url_join( tool_shed_url, 'repository/find_tools?galaxy_url=%s&webapp=galaxy' % galaxy_url )
return trans.response.send_redirect( url )
@web.expose
@web.require_admin
def find_workflows_in_tool_shed( self, trans, **kwd ):
tool_shed_url = kwd[ 'tool_shed_url' ]
galaxy_url = url_for( '/', qualified=True )
- url = '%srepository/find_workflows?galaxy_url=%s&webapp=galaxy' % ( tool_shed_url, galaxy_url )
+ url = url_join( tool_shed_url, 'repository/find_workflows?galaxy_url=%s&webapp=galaxy' % galaxy_url )
return trans.response.send_redirect( url )
def generate_tool_path( self, repository_clone_url, changeset_revision ):
"""
@@ -489,7 +489,7 @@
tool_shed_url = items[ 0 ]
repo_path = items[ 1 ]
tool_shed_url = clean_tool_shed_url( tool_shed_url )
- return '%s/repos%s/%s' % ( tool_shed_url, repo_path, changeset_revision )
+ return url_join( tool_shed_url, 'repos', repo_path, changeset_revision )
@web.json
@web.require_admin
def get_file_contents( self, trans, file_path ):
@@ -634,8 +634,8 @@
tool_shed_repository,
trans.model.ToolShedRepository.installation_status.SETTING_TOOL_VERSIONS )
tool_shed_url = get_url_from_repository_tool_shed( trans.app, tool_shed_repository )
- url = '%s/repository/get_tool_versions?name=%s&owner=%s&changeset_revision=%s&webapp=galaxy' % \
- ( tool_shed_url, tool_shed_repository.name, tool_shed_repository.owner, tool_shed_repository.changeset_revision )
+ url = url_join( tool_shed_url, '/repository/get_tool_versions?name=%s&owner=%s&changeset_revision=%s&webapp=galaxy' % \
+ ( tool_shed_repository.name, tool_shed_repository.owner, tool_shed_repository.changeset_revision ) )
response = urllib2.urlopen( url )
text = response.read()
response.close()
@@ -954,7 +954,7 @@
repository_ids = kwd.get( 'repository_ids', None )
changeset_revisions = kwd.get( 'changeset_revisions', None )
# Get the information necessary to install each repository.
- url = '%srepository/get_repository_information?repository_ids=%s&changeset_revisions=%s&webapp=galaxy' % ( tool_shed_url, repository_ids, changeset_revisions )
+ url = url_join( tool_shed_url, 'repository/get_repository_information?repository_ids=%s&changeset_revisions=%s&webapp=galaxy' % ( repository_ids, changeset_revisions ) )
response = urllib2.urlopen( url )
raw_text = response.read()
response.close()
@@ -1097,8 +1097,8 @@
name = repo_info_dict.keys()[ 0 ]
repo_info_tuple = repo_info_dict[ name ]
description, repository_clone_url, changeset_revision, ctx_rev, repository_owner, tool_dependencies = repo_info_tuple
- url = '%srepository/get_readme?name=%s&owner=%s&changeset_revision=%s&webapp=galaxy' % \
- ( tool_shed_url, name, repository_owner, changeset_revision )
+ url = url_join( tool_shed_url, 'repository/get_readme?name=%s&owner=%s&changeset_revision=%s&webapp=galaxy' % \
+ ( name, repository_owner, changeset_revision ) )
response = urllib2.urlopen( url )
raw_text = response.read()
response.close()
@@ -1273,8 +1273,8 @@
tool_shed = get_tool_shed_from_clone_url( repository_clone_url )
# Get all previous change set revisions from the tool shed for the repository back to, but excluding, the previous valid changeset
# revision to see if it was previously installed using one of them.
- url = '%s/repository/previous_changeset_revisions?galaxy_url=%s&name=%s&owner=%s&changeset_revision=%s&webapp=galaxy' % \
- ( tool_shed_url, url_for( '/', qualified=True ), repository_name, repository_owner, changeset_revision )
+ url = url_join( tool_shed_url, 'repository/previous_changeset_revisions?galaxy_url=%s&name=%s&owner=%s&changeset_revision=%s&webapp=galaxy' % \
+ ( url_for( '/', qualified=True ), repository_name, repository_owner, changeset_revision ) )
response = urllib2.urlopen( url )
text = response.read()
response.close()
@@ -1350,8 +1350,8 @@
# Get the tool_versions from the tool shed for each tool in the installed change set.
repository = get_repository( trans, kwd[ 'id' ] )
tool_shed_url = get_url_from_repository_tool_shed( trans.app, repository )
- url = '%s/repository/get_tool_versions?name=%s&owner=%s&changeset_revision=%s&webapp=galaxy' % \
- ( tool_shed_url, repository.name, repository.owner, repository.changeset_revision )
+ url = url_join( tool_shed_url, 'repository/get_tool_versions?name=%s&owner=%s&changeset_revision=%s&webapp=galaxy' % \
+ ( repository.name, repository.owner, repository.changeset_revision ) )
response = urllib2.urlopen( url )
text = response.read()
response.close()
@@ -1522,7 +1522,7 @@
def __generate_clone_url( self, trans, repository ):
"""Generate the URL for cloning a repository."""
tool_shed_url = get_url_from_repository_tool_shed( trans.app, repository )
- return '%s/repos/%s/%s' % ( tool_shed_url, repository.owner, repository.name )
+ return url_join( tool_shed_url, 'repos', repository.owner, repository.name )
## ---- Utility methods -------------------------------------------------------
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: greg: Add the ability to browse writable repositories in a tool shed.
by Bitbucket 28 Aug '12
by Bitbucket 28 Aug '12
28 Aug '12
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/changeset/c87370c5340d/
changeset: c87370c5340d
user: greg
date: 2012-08-28 17:01:07
summary: Add the ability to browse writable repositories in a tool shed.
affected #: 2 files
diff -r 5adbc8515631847cb66378ea28e644344d890265 -r c87370c5340d359d72301234a958c138adfecd7e lib/galaxy/webapps/community/controllers/repository.py
--- a/lib/galaxy/webapps/community/controllers/repository.py
+++ b/lib/galaxy/webapps/community/controllers/repository.py
@@ -246,6 +246,25 @@
grids.GridAction( "User preferences", dict( controller='user', action='index', cntrller='repository', webapp='community' ) )
]
+class WritableRepositoryListGrid( RepositoryListGrid ):
+ def build_initial_query( self, trans, **kwd ):
+ # TODO: improve performance by adding a db table associating users with repositories for which they have write access.
+ username = kwd[ 'username' ]
+ clause_list = []
+ for repository in trans.sa_session.query( self.model_class ):
+ allow_push_usernames = repository.allow_push.split( ',' )
+ if username in allow_push_usernames:
+ clause_list.append( self.model_class.table.c.id == repository.id )
+ if clause_list:
+ return trans.sa_session.query( self.model_class ) \
+ .filter( or_( *clause_list ) ) \
+ .join( model.User.table ) \
+ .outerjoin( model.RepositoryCategoryAssociation.table ) \
+ .outerjoin( model.Category.table )
+ # Return an empty query.
+ return trans.sa_session.query( self.model_class ) \
+ .filter( self.model_class.table.c.id < 0 )
+
class ValidRepositoryListGrid( RepositoryListGrid ):
class CategoryColumn( grids.TextColumn ):
def get_value( self, trans, grid, repository ):
@@ -393,6 +412,7 @@
email_alerts_repository_list_grid = EmailAlertsRepositoryListGrid()
category_list_grid = CategoryListGrid()
valid_category_list_grid = ValidCategoryListGrid()
+ writable_repository_list_grid = WritableRepositoryListGrid()
def __add_hgweb_config_entry( self, trans, repository, repository_path ):
# Add an entry in the hgweb.config file for a new repository. An entry looks something like:
@@ -519,12 +539,15 @@
repository_id = kwd.get( 'id', None )
repository = get_repository( trans, repository_id )
kwd[ 'f-email' ] = repository.user.email
- elif operation == "my_repositories":
+ elif operation == "repositories_i_own":
# Eliminate the current filters if any exist.
for k, v in kwd.items():
if k.startswith( 'f-' ):
del kwd[ k ]
kwd[ 'f-email' ] = trans.user.email
+ elif operation == "writable_repositories":
+ kwd[ 'username' ] = trans.user.username
+ return self.writable_repository_list_grid( trans, **kwd )
elif operation == "repositories_by_category":
# Eliminate the current filters if any exist.
for k, v in kwd.items():
diff -r 5adbc8515631847cb66378ea28e644344d890265 -r c87370c5340d359d72301234a958c138adfecd7e templates/webapps/community/index.mako
--- a/templates/webapps/community/index.mako
+++ b/templates/webapps/community/index.mako
@@ -60,34 +60,41 @@
%endif
<div class="toolSectionPad"></div><div class="toolSectionTitle">
- Repositories
+ All Repositories
</div>
- <div class="toolSectionBody">
- <div class="toolSectionBg">
- <div class="toolTitle">
- <a target="galaxy_main" href="${h.url_for( controller='repository', action='browse_categories', webapp='community' )}">Browse by category</a>
- </div>
- %if trans.user:
- <div class="toolTitle">
- <a target="galaxy_main" href="${h.url_for( controller='repository', action='browse_repositories', operation='my_repositories', webapp='community' )}">Browse my repositories</a>
- </div>
- <div class="toolTitle">
- <a target="galaxy_main" href="${h.url_for( controller='repository', action='browse_invalid_tools', cntrller='repository', webapp='community' )}">Browse my invalid tools</a>
- </div>
- %endif
+ <div class="toolTitle">
+ <a target="galaxy_main" href="${h.url_for( controller='repository', action='browse_categories', webapp='community' )}">Browse by category</a>
+ </div>
+ %if trans.user:
+ <div class="toolSectionPad"></div>
+ <div class="toolSectionTitle">
+ My Repositories and Tools
</div>
- </div>
- <div class="toolSectionBody">
- <div class="toolSectionBg">
- <div class="toolTitle">
- %if trans.user:
- <a target="galaxy_main" href="${h.url_for( controller='repository', action='create_repository', webapp='community' )}">Create new repository</a>
- %else:
- <a target="galaxy_main" href="${h.url_for( controller='/user', action='login', webapp='community' )}">Login to create a repository</a>
- %endif
- </div>
+ <div class="toolTitle">
+ <a target="galaxy_main" href="${h.url_for( controller='repository', action='browse_repositories', operation='repositories_i_own', webapp='community' )}">Repositories I own</a></div>
- </div>
+ <div class="toolTitle">
+ <a target="galaxy_main" href="${h.url_for( controller='repository', action='browse_repositories', operation='writable_repositories', webapp='community' )}">My writable repositories</a>
+ </div>
+ <div class="toolTitle">
+ <a target="galaxy_main" href="${h.url_for( controller='repository', action='browse_invalid_tools', cntrller='repository', webapp='community' )}">My invalid tools</a>
+ </div>
+ <div class="toolSectionPad"></div>
+ <div class="toolSectionTitle">
+ Available Actions
+ </div>
+ <div class="toolTitle">
+ <a target="galaxy_main" href="${h.url_for( controller='repository', action='create_repository', webapp='community' )}">Create new repository</a>
+ </div>
+ %else:
+ <div class="toolSectionPad"></div>
+ <div class="toolSectionTitle">
+ Available Actions
+ </div>
+ <div class="toolTitle">
+ <a target="galaxy_main" href="${h.url_for( controller='/user', action='login', webapp='community' )}">Login to create a repository</a>
+ </div>
+ %endif
</div></div></div>
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
28 Aug '12
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/changeset/5adbc8515631/
changeset: 5adbc8515631
user: jgoecks
date: 2012-08-28 15:05:31
summary: Fixes for phyloviz parser and a4c7aeb61c7b.
affected #: 2 files
diff -r a4c7aeb61c7b8e76fcf3fd96d0d351be88d1c1d1 -r 5adbc8515631847cb66378ea28e644344d890265 lib/galaxy/visualization/phyloviz/phyloviz_dataprovider.py
--- a/lib/galaxy/visualization/phyloviz/phyloviz_dataprovider.py
+++ b/lib/galaxy/visualization/phyloviz/phyloviz_dataprovider.py
@@ -1,6 +1,6 @@
from newickparser import Newick_Parser
from nexusparser import Nexus_Parser
-#from phyloxmlparser import Phyloxml_Parser
+from phyloxmlparser import Phyloxml_Parser
class Phyloviz_DataProvider(object):
@@ -16,9 +16,9 @@
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 == "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)
diff -r a4c7aeb61c7b8e76fcf3fd96d0d351be88d1c1d1 -r 5adbc8515631847cb66378ea28e644344d890265 lib/galaxy/visualization/phyloviz/phyloxmlparser.py
--- a/lib/galaxy/visualization/phyloviz/phyloxmlparser.py
+++ b/lib/galaxy/visualization/phyloviz/phyloxmlparser.py
@@ -1,8 +1,5 @@
from baseparser import Base_Parser, PhyloTree, Node
-
-'''
-TOD0: use native Python XML parser.
-from lxml import etree
+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"""
@@ -22,7 +19,7 @@
"""passes a file and extracts its Phylogeny Tree content."""
phyloXmlFile = open(filePath, "r")
- xmlTree = etree.parse(phyloXmlFile)
+ 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
@@ -134,16 +131,4 @@
def cleanTag(self, tagString):
return tagString[self.nameSpaceIndex:]
-
-
-if __name__=="__main__":
-
- # Files tested against
- parser = Phyloxml_Parser()
- filepath = "../data/" +"apaf.xml"
- # filepath = "../data/" +"12_multiple_supports.xml"
-
- # filepath = "../data/" +"bcl_2.xml"
- # filepath = "../data/" +"reducedXml.xml"
- parser.parseFile(filepath)
-'''
\ No newline at end of file
+
\ 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: Comment out phyloviz XML parser until native Python XML parsing is used.
by Bitbucket 27 Aug '12
by Bitbucket 27 Aug '12
27 Aug '12
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/changeset/a4c7aeb61c7b/
changeset: a4c7aeb61c7b
user: jgoecks
date: 2012-08-27 21:44:01
summary: Comment out phyloviz XML parser until native Python XML parsing is used.
affected #: 2 files
diff -r 75a03bacdc7a3dc5b1c03f8b02df0ab383366955 -r a4c7aeb61c7b8e76fcf3fd96d0d351be88d1c1d1 lib/galaxy/visualization/phyloviz/phyloviz_dataprovider.py
--- a/lib/galaxy/visualization/phyloviz/phyloviz_dataprovider.py
+++ b/lib/galaxy/visualization/phyloviz/phyloviz_dataprovider.py
@@ -1,6 +1,6 @@
from newickparser import Newick_Parser
from nexusparser import Nexus_Parser
-from phyloxmlparser import Phyloxml_Parser
+#from phyloxmlparser import Phyloxml_Parser
class Phyloviz_DataProvider(object):
@@ -16,9 +16,9 @@
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 == "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)
diff -r 75a03bacdc7a3dc5b1c03f8b02df0ab383366955 -r a4c7aeb61c7b8e76fcf3fd96d0d351be88d1c1d1 lib/galaxy/visualization/phyloviz/phyloxmlparser.py
--- a/lib/galaxy/visualization/phyloviz/phyloxmlparser.py
+++ b/lib/galaxy/visualization/phyloviz/phyloxmlparser.py
@@ -1,4 +1,7 @@
from baseparser import Base_Parser, PhyloTree, Node
+
+'''
+TOD0: use native Python XML parser.
from lxml import etree
class Phyloxml_Parser(Base_Parser):
@@ -143,3 +146,4 @@
# filepath = "../data/" +"bcl_2.xml"
# filepath = "../data/" +"reducedXml.xml"
parser.parseFile(filepath)
+'''
\ 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
2 new commits in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/changeset/f6d9557b6d77/
changeset: f6d9557b6d77
user: Tomithy
date: 2012-08-26 12:22:23
summary: re-integrated phyloviz to a new fork of galaxy-central with a =
tat of minor touch up; save and edit now works
affected #: 19 files
diff -r b1f2c51d6bd8d8b1aecce8f62304cc2df278ccec -r f6d9557b6d77bde1c8049ba=
ffb65374729d51b89 lib/galaxy/datatypes/data.py
--- a/lib/galaxy/datatypes/data.py
+++ b/lib/galaxy/datatypes/data.py
@@ -719,7 +719,49 @@
pass
=20
class Newick( Text ):
- pass
+ """New Hampshire/Newick Format"""
+ file_ext =3D "nhx"
+
+ MetadataElement( name=3D"columns", default=3D3, desc=3D"Number of colu=
mns", readonly=3DTrue )
+
+ def __init__(self, **kwd):
+ """Initialize foobar datatype"""
+ Text.__init__(self, **kwd)
+
+ def init_meta( self, dataset, copy_from=3DNone ):
+ Text.init_meta( self, dataset, copy_from=3Dcopy_from )
+
+
+ def sniff( self, filename ):
+ """ Returning false as the newick format is too general and cannot=
be sniffed."""
+ return False
+
+
+class Nexus( Text ):
+ """Nexus format as used By Paup, Mr Bayes, etc"""
+ file_ext =3D "nex"
+
+ MetadataElement( name=3D"columns", default=3D3, desc=3D"Number of colu=
mns", readonly=3DTrue )
+
+ def __init__(self, **kwd):
+ """Initialize foobar datatype"""
+ Text.__init__(self, **kwd)
+
+ def init_meta( self, dataset, copy_from=3DNone ):
+ Text.init_meta( self, dataset, copy_from=3Dcopy_from )
+
+
+ def sniff( self, filename ):
+ """All Nexus Files Simply puts a '#NEXUS' in its first line"""
+ f =3D open(filename, "r")
+ firstline =3D f.readline().upper()
+ f.close()
+
+ if "#NEXUS" in firstline:
+ return True
+ else:
+ return False
+
=20
# ------------- Utility methods --------------
=20
diff -r b1f2c51d6bd8d8b1aecce8f62304cc2df278ccec -r f6d9557b6d77bde1c8049ba=
ffb65374729d51b89 lib/galaxy/datatypes/xml.py
--- a/lib/galaxy/datatypes/xml.py
+++ b/lib/galaxy/datatypes/xml.py
@@ -76,3 +76,24 @@
dataset.blurb =3D 'file purged from disk'
def sniff( self, filename ):
return False
+
+class Phyloxml( GenericXml ):
+ """Format for defining phyloxml data http://www.phyloxml.org/"""
+ file_ext =3D "phyloxml"
+ def set_peek( self, dataset, is_multi_byte=3DFalse ):
+ """Set the peek and blurb text"""
+ if not dataset.dataset.purged:
+ dataset.peek =3D data.get_file_peek( dataset.file_name, is_mul=
ti_byte=3Dis_multi_byte )
+ dataset.blurb =3D 'Phyloxml data'
+ else:
+ dataset.peek =3D 'file does not exist'
+ dataset.blurb =3D 'file purged from disk'
+
+ def sniff( self, filename ):
+ """"Checking for keyword - 'phyloxml' always in lowercase in the f=
irst few lines"""
+ f =3D open(filename, "r")
+ firstlines =3D "".join(f.readlines(5))
+ f.close()
+ if "phyloxml" in firstlines:
+ return True
+ return False
\ No newline at end of file
diff -r b1f2c51d6bd8d8b1aecce8f62304cc2df278ccec -r f6d9557b6d77bde1c8049ba=
ffb65374729d51b89 lib/galaxy/visualization/phyloviz/__init__.py
--- /dev/null
+++ b/lib/galaxy/visualization/phyloviz/__init__.py
@@ -0,0 +1,1 @@
+__author__ =3D 'Tomithy'
diff -r b1f2c51d6bd8d8b1aecce8f62304cc2df278ccec -r f6d9557b6d77bde1c8049ba=
ffb65374729d51b89 lib/galaxy/visualization/phyloviz/baseparser.py
--- /dev/null
+++ b/lib/galaxy/visualization/phyloviz/baseparser.py
@@ -0,0 +1,125 @@
+import json
+
+class Node(object):
+ """Node class of PhyloTree, which represents a CLAUDE in a phylogeneti=
c tree"""
+ def __init__(self, nodeName, **kwargs):
+ """Creates a node and adds in the typical annotations"""
+ self.name, self.id =3D nodeName, kwargs.get("id", 0)
+ self.depth =3D kwargs.get("depth", 0)
+ self.children =3D []
+
+ self.isInternal =3D kwargs.get("isInternal", 0)
+ self.length, self.bootstrap =3D kwargs.get("length", 0), kwargs.ge=
t("bootstrap", None)
+ self.events =3D kwargs.get("events", "")
+
+ # clean up boot strap values
+ if self.bootstrap =3D=3D -1:
+ self.bootstrap =3D None
+
+ def addChildNode(self, child):
+ """Adds a child node to the current node"""
+ if isinstance(child, Node):
+ self.children.append(child)
+ else:
+ self.children +=3D 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 =3D {
+ "name" : self.name,
+ "id" : self.id,
+ "depth" : self.depth,
+ "dist" : self.length
+ }
+ thisJson =3D self.addChildrenToJson(thisJson)
+ thisJson =3D self.addMiscToJson(thisJson)
+ return thisJson
+
+ def addChildrenToJson(self, jsonDict):
+ """Needs a special method to addChildren, such that the key does n=
ot 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 =3D [ node.toJson() for node in self.children]
+ jsonDict["children"] =3D children
+ return jsonDict
+
+
+ def addMiscToJson(self, jsonDict):
+ """Adds other misc attributes to json if they are present"""
+ if not self.events =3D=3D "":
+ jsonDict["events"] =3D self.events
+ if not self.bootstrap =3D=3D None:
+ jsonDict["bootstrap"] =3D 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 =3D None, {}
+ self.nodes =3D {}
+ self.title =3D None
+ self.id =3D 1
+
+ def addAttributesToRoot(self, attrDict):
+ """Adds attributes to root, but first we put it in a temp store an=
d bind it with root when .toJson is called"""
+ for key, value in attrDict.items():
+ self.rootAttr[key] =3D 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"] =3D self.id
+ self.id +=3D 1
+ return Node(nodeName, **kwargs)
+
+ def addRoot(self, root):
+ """Creates a root for phyloTree"""
+ assert isinstance(root, Node)
+ root.parent =3D None
+ self.root =3D root
+
+ def generateJsonableDict(self):
+ """Changes itself into a dictonary by recurssively calling the toj=
son on all its nodes. Think of it
+ as a dict in an array of dict in an array of dict and so on..."""
+ jsonTree =3D ""
+ if self.root:
+ assert isinstance(self.root, Node)
+ jsonTree =3D self.root.toJson()
+ for key, value in self.rootAttr.items():
+ # transfer temporary stored attr to root
+ jsonTree[key] =3D value
+ else:
+ raise Exception("Root is not assigned!")
+ return jsonTree
+
+
+
+class Base_Parser(object):
+ """Base parsers contain all the methods to handle phylogeny tree creat=
ion and
+ converting the data to json that all parsers should have"""
+
+ def __init__(self):
+ self.phyloTrees =3D []
+
+ def parseFile(self, filePath):
+ """Base method that all phylogeny file parser should have"""
+ raise Exception("Base method for phylogeny file parsers is not imp=
lemented")
+
+ 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 =3D open(filepath, "w")
+ f.writelines(json)
+ f.close()
diff -r b1f2c51d6bd8d8b1aecce8f62304cc2df278ccec -r f6d9557b6d77bde1c8049ba=
ffb65374729d51b89 lib/galaxy/visualization/phyloviz/newickparser.py
--- /dev/null
+++ b/lib/galaxy/visualization/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 b=
y 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: json=
ableDict"""
+ with open(filePath, "r") as newickFile:
+ newickString =3D newickFile.read()
+ newickString =3D 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: j=
sonableDict"""
+ return self._parseNewickToJson(newickString)
+
+
+ def _parseNewickToJson(self, newickString, treeName=3DNone, nameMap=3D=
None):
+ """parses a newick representation of a tree into a PhyloTree data =
structure,
+ which can be easily converted to json"""
+ self.phyloTree =3D PhyloTree()
+ newickString =3D self.cleanNewickString(newickString)
+ if nameMap:
+ newickString =3D self._mapName(newickString, nameMap)
+
+ self.phyloTree.root =3D 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 wh=
ite spaces"""
+ return re.sub(r'\s|;|\"|\'|\\', '', rawNewick)
+
+
+ def _makeNodesFromString(self, string, depth):
+ """elements separated by comma could be empty"""
+
+ if string.find("(") !=3D -1:
+ raise Exception("Tree is not well form, location: " + string)
+
+ childrenString =3D string.split(",")
+ childrenNodes =3D []
+
+ for childString in childrenString:
+ if len(childString) =3D=3D 0:
+ continue
+ nodeInfo =3D childString.split(":")
+ name, length, bootstrap =3D "", None, -1
+ if len(nodeInfo) =3D=3D 2: # has length info
+ length =3D nodeInfo[1]
+ # checking for bootstap values
+ name =3D nodeInfo[0]
+ try: # Nexus may bootstrap in names position
+ name =3D float(name)
+ if 0<=3D name <=3D 1:
+ bootstrap =3D name
+ elif 1 <=3D name <=3D 100:
+ bootstrap =3D name / 100
+ name =3D ""
+ except ValueError:
+ name =3D nodeInfo[0]
+ else:
+ name =3D nodeInfo[0] # string only contains name
+ node =3D self.phyloTree.makeNode(name, length=3Dlength, depth=
=3Ddepth, bootstrap=3D bootstrap)
+ childrenNodes +=3D [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 outsi=
de of quotes(" ")
+ """
+ newString =3D ""
+ start =3D 0
+ end =3D 0
+
+ for i in xrange(len(newickString)):
+ if newickString[i] =3D=3D "(" or newickString[i] =3D=3D ",":
+ if re.match(r"[,(]", newickString[i+1:]):
+ continue
+ else:
+ end =3D 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 t=
erm
+ for j in xrange(i+1, len(newickString)):
+ enclosingSymbol =3D newickString[j] # the immedi=
ate symbol after a common or left bracket which denotes the end of a term
+ if enclosingSymbol =3D=3D ")" or enclosingSymbol =
=3D=3D ":" or enclosingSymbol =3D=3D ",":
+ termToReplace =3D newickString[end:j]
+
+ newString +=3D newickString[start : end] + na=
meMap[termToReplace] #+ "'" "'" +
+ start =3D j
+ break
+
+ newString +=3D 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 no=
de C, its children D, E,
+ and finally the succeeding nodes F, G"""
+
+ # Base case where there is only an empty string
+ if string =3D=3D "":
+ return
+ # Base case there its only an internal claude
+ if string.find("(") =3D=3D -1:
+ return self._makeNodesFromString(string, depth)
+
+ nodes, children =3D [], [] # nodes refer to the nodes on this=
level, children refers to the child of the
+ start =3D 0
+ lenOfPreceedingInternalNodeString =3D 0
+ bracketStack =3D []
+
+ for j in xrange(len(string)):
+ if string[j] =3D=3D "(": #finding the positions of all the =
open brackets
+ bracketStack.append(j)
+ continue
+ if string[j] =3D=3D ")": #finding the positions of all the =
closed brackets to extract claude
+ i =3D bracketStack.pop()
+
+ if len(bracketStack) =3D=3D 0: # is child of current node
+
+ InternalNode =3D None
+
+ #First flat call to make nodes of the same depth but f=
rom the preceeding string.
+ startSubstring =3D string[start + lenOfPreceedingInter=
nalNodeString: i]
+ preceedingNodes =3D self._makeNodesFromString(startSu=
bstring, depth)
+ nodes +=3D preceedingNodes
+
+ # Then We will try to see if the substring has any int=
ernal nodes first, make it then make nodes preceeding it and succeeding it.
+ if j + 1 < len(string):
+ stringRightOfBracket =3D string[j+1:] # Eg. '=
(b:0.4,a:0.3)c:0.3, stringRightOfBracket =3D c:0.3
+ match =3D re.search(r"[\)\,\(]", stringRightOfBrac=
ket)
+ if match:
+ indexOfNextSymbol =3D match.start()
+ stringRepOfInternalNode =3D stringRightOfBrack=
et[:indexOfNextSymbol]
+ internalNodes =3D self._makeNodesFromString( s=
tringRepOfInternalNode, depth)
+ if len(internalNodes) > 0:
+ InternalNode =3D internalNodes[0]
+ lenOfPreceedingInternalNodeString =3D len(stri=
ngRepOfInternalNode)
+ else: # sometimes the node can be the last eleme=
nt of a string
+ InternalNode =3D self._makeNodesFromString(str=
ing[j+1:], depth)[0]
+ lenOfPreceedingInternalNodeString =3D len(stri=
ng) - j
+ if InternalNode =3D=3D None: #creating a generic=
node if it is unnamed
+ InternalNode =3D self.phyloTree.makeNode( "", dept=
h=3Ddepth, isInternal=3DTrue ) #"internal-" + str(depth)
+ lenOfPreceedingInternalNodeString =3D 0
+
+ # recussive call to make the internal claude
+ childSubString =3D string[ i + 1 : j ]
+ InternalNode.addChildNode(self.parseNode(childSubStrin=
g, depth + 1))
+
+ nodes.append(InternalNode) # we append the internal n=
ode later to preserve order
+
+ start =3D j + 1
+ continue
+
+ if depth =3D=3D 0: # if its the root node, we do nothing about =
it and return
+ return nodes[0]
+
+ # Adding last most set of children
+ endString =3D string[start:]
+ if string[start-1] =3D=3D ")": # if the symbol belongs to an inte=
rnal node which is created previously, then we remove it from the string le=
ft to parse
+ match =3D re.search(r"[\)\,\(]", endString)
+ if match:
+ endOfNodeName =3D start + match.start() + 1
+ endString =3D string[endOfNodeName:]
+ nodes +=3D self._makeNodesFromString(endString, depth)
+
+ return nodes
diff -r b1f2c51d6bd8d8b1aecce8f62304cc2df278ccec -r f6d9557b6d77bde1c8049ba=
ffb65374729d51b89 lib/galaxy/visualization/phyloviz/nexusparser.py
--- /dev/null
+++ b/lib/galaxy/visualization/phyloviz/nexusparser.py
@@ -0,0 +1,107 @@
+from newickparser import Newick_Parser
+import re
+
+MAX_READLINES =3D 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 be=
gin and another line starting with end;
+ Commends inside square brackets are to be ignored,
+ For more information: http://wiki.christophchamp.com/index.php/NEX=
US_file_format
+ Nexus can store multiple trees
+ """
+
+ with open( filename, "rt") as nex_file:
+ nexlines =3D nex_file.readlines()
+
+ rowCount =3D 0
+ inTreeBlock =3D False # sentinel to check if we are in a t=
ree block
+ intranslateBlock =3D False # sentinel to check if we are in the=
translate region of the tree. Stores synonyms of the labellings
+ self.inCommentBlock =3D False
+ self.nameMapping =3D None # stores mapping representation us=
ed in nexus format
+ treeNames =3D []
+
+ for line in nexlines:
+ line =3D line.replace(";\n", "")
+ lline =3D line.lower()
+
+ if rowCount > MAX_READLINES or (not nex_file) :
+ break
+ rowCount +=3D1
+ # We are only interested in the tree block.
+ if "begin" in lline and "tree" in lline and not inTreeBlock:
+ inTreeBlock =3D True
+ continue
+ if inTreeBlock and "end" in lline[:3]:
+ inTreeBlock, currPhyloTree =3D False, None
+ continue
+
+ if inTreeBlock:
+
+ if "title" in lline: # Adding title to the tree
+ titleLoc =3D lline.find("title")
+ title =3D line[titleLoc + 5:].replace(" ", "")
+
+ continue
+
+ if "translate" in lline:
+ intranslateBlock =3D True
+ self.nameMapping =3D {}
+ continue
+
+ if intranslateBlock:
+ mappingLine =3D self.splitLinebyWhitespaces(line)
+ key, value =3D mappingLine[1], mappingLine[2].replace(=
",", "").replace("'","") #replacing illegal json characters
+ self.nameMapping[key] =3D value
+
+ # Extracting newick Trees
+ if "tree" in lline:
+ intranslateBlock =3D False
+
+ treeLineCols =3D self.splitLinebyWhitespaces(line)
+ treeName, newick =3D treeLineCols[2], treeLineCols[-1]
+
+ if newick =3D=3D "": # Empty lines can be found in =
tree blocks
+ continue
+
+ currPhyloTree =3D self._parseNewickToJson(newick, tree=
Name, nameMap=3Dself.nameMapping)
+
+ self.phyloTrees.append(currPhyloTree)
+ treeIndex =3D len(self.phyloTrees) - 1
+ treeNames.append( (treeName, treeIndex) ) # appendi=
ng 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 ca=
n 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 =3D 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 an=
other is open.
+ else:
+ self.inCommentBlock =3D False
+ return "Nextline" # need to move on to the nextline =
after getting out of comment
+ return ""
\ No newline at end of file
diff -r b1f2c51d6bd8d8b1aecce8f62304cc2df278ccec -r f6d9557b6d77bde1c8049ba=
ffb65374729d51b89 lib/galaxy/visualization/phyloviz/phyloviz_dataprovider.py
--- /dev/null
+++ b/lib/galaxy/visualization/phyloviz/phyloviz_dataprovider.py
@@ -0,0 +1,35 @@
+from newickparser import Newick_Parser
+from nexusparser import Nexus_Parser
+from phyloxmlparser import Phyloxml_Parser
+
+class Phyloviz_DataProvider(object):
+
+ def __init__(self):
+ pass
+
+ def parseFile(self, filepath, fileExt):
+ """returns [trees], meta
+ Trees are actually an array of JsonDicts. It's usually one tre=
e, except in the case of Nexus
+ """
+ jsonDicts, meta =3D [], {}
+ try:
+ if fileExt =3D=3D "nhx": # parses newick files
+ newickParser =3D Newick_Parser()
+ jsonDicts, parseMsg =3D newickParser.parseFile(filepath)
+ elif fileExt =3D=3D "phyloxml": # parses phyloXML files
+ phyloxmlParser =3D Phyloxml_Parser()
+ jsonDicts, parseMsg =3D phyloxmlParser.parseFile(filepath)
+ elif fileExt =3D=3D "nex": # parses nexus files
+ nexusParser =3D Nexus_Parser()
+ jsonDicts, parseMsg =3D nexusParser.parseFile(filepath)
+ meta["trees"] =3D parseMsg
+ else:
+ raise Exception("File type is not supported")
+
+ meta["msg"] =3D parseMsg
+
+ except Exception:
+ jsonDicts, meta["msg"] =3D [], "Parse failed"
+
+ return jsonDicts, meta
+
diff -r b1f2c51d6bd8d8b1aecce8f62304cc2df278ccec -r f6d9557b6d77bde1c8049ba=
ffb65374729d51b89 lib/galaxy/visualization/phyloviz/phyloxmlparser.py
--- /dev/null
+++ b/lib/galaxy/visualization/phyloviz/phyloxmlparser.py
@@ -0,0 +1,145 @@
+from baseparser import Base_Parser, PhyloTree, Node
+from lxml import etree
+
+class Phyloxml_Parser(Base_Parser):
+ """Parses a phyloxml file into a json file that will be passed to Phyl=
oViz for display"""
+
+ def __init__(self):
+ super(Phyloxml_Parser, self).__init__()
+ self.phyloTree =3D PhyloTree()
+ self.tagsOfInterest =3D {
+ "clade": "",
+ "name" : "name",
+ "branch_length" : "length",
+ "confidence" : "bootstrap",
+ "events" : "events"
+ }
+
+ def parseFile(self, filePath):
+ """passes a file and extracts its Phylogeny Tree content."""
+ phyloXmlFile =3D open(filePath, "r")
+
+ xmlTree =3D etree.parse(phyloXmlFile)
+ xmlRoot =3D xmlTree.getroot()[0]
+ self.nameSpaceIndex =3D xmlRoot.tag.rfind("}") + 1 # used later by=
the clean tag method to remove the name space in every element.tag
+
+ phyloRoot =3D None
+ for child in xmlRoot:
+ childTag =3D self.cleanTag(child.tag)
+ if childTag =3D=3D "clade":
+ phyloRoot =3D child
+ elif childTag =3D=3D "name":
+ self.phyloTree.title =3D child.text
+
+ self.phyloTree.root =3D self.parseNode(phyloRoot, 0)
+ jsonDict =3D 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 =3D self.cleanTag(node.tag)
+ if not tag =3D=3D "clade":
+ return None
+ hasInnerClade =3D False
+
+ # peeking once for parent and once for child to check if the node =
is internal
+ for child in node:
+ childTag =3D self.cleanTag(child.tag)
+ if childTag =3D=3D "clade":
+ hasInnerClade =3D True
+ break
+
+ if hasInnerClade: # this node is an internal node
+ currentNode =3D self._makeInternalNode(node, depth=3D depth)
+ for child in node:
+ child =3D self.parseNode(child, depth + 1)
+ if isinstance(child, Node):
+ currentNode.addChildNode(child)
+
+ else: # this node is a leaf node
+ currentNode =3D self._makeLeafNode(node, depth=3Ddepth+1)
+
+ return currentNode
+
+
+ def _makeLeafNode(self, leafNode, depth =3D 0 ):
+ """Makes leaf nodes by calling Phylotree methods"""
+ node =3D {}
+ for child in leafNode:
+ childTag =3D self.cleanTag(child.tag)
+ if childTag in self.tagsOfInterest:
+ key =3D self.tagsOfInterest[childTag] # need to map phy=
loxml terms to ours
+ node[key] =3D child.text
+
+ node["depth"] =3D depth
+ return self.phyloTree.makeNode(self._getNodeName(leafNode), **node)
+
+ def _getNodeName(self, node, depth=3D-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 t=
o be treated differently as the name
+ is embedded one level deeper"""
+ phyloxmlTaxoNames =3D {
+ "common_name" : "",
+ "scientific_name" : "",
+ "code" : ""
+ }
+ for child in node:
+ childTag =3D self.cleanTag(child.tag)
+ if childTag in phyloxmlTaxoNames:
+ return child.text
+ return ""
+
+ nodeName =3D ""
+ for child in node:
+ childTag =3D self.cleanTag(child.tag)
+ if childTag =3D=3D "name" :
+ nodeName =3D child.text
+ break
+ elif childTag =3D=3D "taxonomy":
+ nodeName =3D getTagFromTaxonomyNode(child)
+ break
+
+ return nodeName
+
+
+ def _makeInternalNode(self, internalNode, depth=3D0):
+ """ Makes an internal node from an element object that is gurantee=
d 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 =3D {}
+ for child in internalNode:
+ childTag =3D self.cleanTag(child.tag)
+ if childTag =3D=3D "clade":
+ continue
+ elif childTag in self.tagsOfInterest:
+ if childTag =3D=3D "events": # events is nested 1 more =
level deeper than others
+ key, text =3D "events", self.cleanTag(child[0].tag)
+ else:
+ key =3D self.tagsOfInterest[childTag]
+ text =3D child.text
+ node[key] =3D text
+
+
+ return self.phyloTree.makeNode(self._getNodeName(internalNode, dep=
th), **node)
+
+
+ def cleanTag(self, tagString):
+ return tagString[self.nameSpaceIndex:]
+
+
+if __name__=3D=3D"__main__":
+
+ # Files tested against
+ parser =3D Phyloxml_Parser()
+ filepath =3D "../data/" +"apaf.xml"
+ # filepath =3D "../data/" +"12_multiple_supports.xml"
+
+ # filepath =3D "../data/" +"bcl_2.xml"
+ # filepath =3D "../data/" +"reducedXml.xml"
+ parser.parseFile(filepath)
diff -r b1f2c51d6bd8d8b1aecce8f62304cc2df278ccec -r f6d9557b6d77bde1c8049ba=
ffb65374729d51b89 lib/galaxy/web/controllers/phyloviz.py
--- /dev/null
+++ b/lib/galaxy/web/controllers/phyloviz.py
@@ -0,0 +1,97 @@
+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_D=
ataProvider
+
+
+class PhyloVizController( BaseUIController, UsesVisualizationMixin, UsesHi=
storyDatasetAssociationMixin, 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 =3D None, **kwargs ):
+ """
+ The index method is called using phyloviz/ with a dataset id passe=
d in.
+ The relevant data set is then retrieved via get_json_from_datasetI=
d which interfaces with the parser
+ The json representation of the phylogenetic tree along with the co=
nfig is then written in the .mako template and passed back to the user
+ """
+ json, config =3D self.get_json_from_datasetId(trans, dataset_id)
+ config["saved_visualization"] =3D False
+ return trans.fill_template( "visualization/phyloviz.mako", data =
=3D json, config=3Dconfig)
+
+
+ @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 =3D self.get_visualization(trans, id)
+ config =3D self.get_visualization_config(trans, viz)
+ config["saved_visualization"] =3D True
+ data =3D config["root"]
+
+ return trans.fill_template( "visualization/phyloviz.mako", data =
=3D data, config=3Dconfig)
+
+
+ @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 =3D self.get_visualization(trans, viz_id)
+ viz_config =3D self.get_visualization_config(trans, viz)
+ viz_config["saved_visualization"] =3D True
+ return {
+ "data" : viz_config["root"],
+ "config" : viz_config
+ }
+
+
+ @web.expose
+ @web.json
+ def getJsonData(self, trans, dataset_id, treeIndex=3D0):
+ """
+ Method to retrieve data asynchronously via json format. Retriving =
from here rather than
+ making a direct datasets/ call allows for some processing and even=
t capturing
+ """
+ treeIndex =3D int(treeIndex)
+ json, config =3D self.get_json_from_datasetId(trans, dataset_id, t=
reeIndex)
+ packedJson =3D {
+ "data" : json,
+ "config" : config
+ }
+
+ return packedJson
+
+
+ def get_json_from_datasetId(self, trans, dataset_id, treeIndex=3D0):
+ """
+ For interfacing phyloviz controllers with phyloviz visualization d=
ata provider (parsers)
+ """
+ dataset =3D self.get_dataset(trans, dataset_id)
+ fileExt, filepath =3D dataset.ext, dataset.file_name # .name=
stores the name of the dataset from the orginal upload
+ json, config =3D "", {} # config contains propertie=
s of the tree and file
+
+ if fileExt =3D=3D "json":
+ something, json =3D self.get_data(dataset)
+ else:
+ try:
+ pd =3D Phyloviz_DataProvider()
+ json, config =3D pd.parseFile(filepath, fileExt)
+ json =3D json[treeIndex]
+ except Exception:
+ pass
+
+ config["title"] =3D dataset.display_name()
+ config["ext"] =3D fileExt
+ config["dataset_id"] =3D dataset_id
+ config["treeIndex"] =3D treeIndex
+
+ return json, config
diff -r b1f2c51d6bd8d8b1aecce8f62304cc2df278ccec -r f6d9557b6d77bde1c8049ba=
ffb65374729d51b89 lib/galaxy/web/controllers/visualization.py
--- a/lib/galaxy/web/controllers/visualization.py
+++ b/lib/galaxy/web/controllers/visualization.py
@@ -16,6 +16,10 @@
action =3D "paramamonster"
elif item.type =3D=3D "circster":
action =3D "circster"
+ elif item.type =3D=3D "phyloviz":
+ # Support phyloviz
+ controller =3D "phyloviz"
+ action =3D "visualization"
return dict( controller=3Dcontroller, action=3Daction, id=3Ditem.i=
d )
=20
# Grid definition
diff -r b1f2c51d6bd8d8b1aecce8f62304cc2df278ccec -r f6d9557b6d77bde1c8049ba=
ffb65374729d51b89 static/scripts/viz/phyloviz.js
--- /dev/null
+++ b/static/scripts/viz/phyloviz.js
@@ -0,0 +1,955 @@
+var UserMenuBase =3D Backbone.View.extend({
+ /**
+ * Base class of any menus that takes in user interaction. Contains ch=
ecking methods.
+ */
+
+ className: 'UserMenuBase',
+
+ isAcceptableValue : function ($inputKey, min, max) {
+ /**
+ * Check if an input value is a number and falls within max min.
+ */
+ var self =3D this,
+ value =3D $inputKey.val(),
+ fieldName =3D $inputKey.attr("displayLabel") || $inputKey.attr=
("id").replace("phyloViz", "");
+
+ function isNumeric(n) {
+ return !isNaN(parseFloat(n)) && isFinite(n);
+ }
+
+ if (!isNumeric(value)){
+ alert(fieldName + " is not a number!");
+ return false;
+ }
+
+ if ( value > max){
+ alert(fieldName + " is too large.");
+ return false;
+ } else if ( value < min) {
+ alert(fieldName + " is too small.");
+ return false;
+ }
+ return true;
+ },
+
+ hasIllegalJsonCharacters : function($inputKey) {
+ /**
+ * Check if any user string inputs has illegal characters that jso=
n cannot accept
+ */
+ if ($inputKey.val().search(/"|'|\\/) !=3D=3D -1){
+ alert("Named fields cannot contain these illegal characters: d=
ouble quote(\"), single guote(\'), or back slash(\\). ");
+ return true;
+ }
+ return false;
+ }
+});
+
+
+function PhyloTreeLayout() {
+ /**
+ * -- Custom Layout call for phyloViz to suit the needs of a phylogene=
tic tree.
+ * -- Specifically: 1) Nodes have a display display of (=3D evo dist X=
depth separation) from their parent
+ * 2) Nodes must appear in other after they have expa=
nd and contracted
+ */
+
+ var self =3D this,
+ hierarchy =3D d3.layout.hierarchy().sort(null).value(null),
+ height =3D 360, // ! represents both the layout angle and the heig=
ht of the layout, in px
+ layoutMode =3D "Linear",
+ leafHeight =3D 18, // height of each individual leaf node
+ depthSeparation =3D 200, // separation between nodes of different =
depth, in px
+ leafIndex =3D 0, // change to recurssive call
+ defaultDist =3D 0.5, // tree defaults to 0.5 dist if no dist is sp=
ecified
+ maxTextWidth =3D 50; // maximum length of the text labels
+
+
+ self.leafHeight =3D function(inputLeafHeight){
+ if (typeof inputLeafHeight =3D=3D=3D "undefined"){ return leafHeig=
ht; }
+ else { leafHeight =3D inputLeafHeight; return self;}
+ };
+
+ self.layoutMode =3D function(mode){
+ if (typeof mode =3D=3D=3D "undefined"){ return layoutMode; }
+ else { layoutMode =3D mode; return self;}
+ };
+
+ self.layoutAngle =3D function(angle) { // changes the layout angle =
of the display, which is really changing the height
+ if (typeof angle =3D=3D=3D "undefined"){ return height; }
+ if (isNaN(angle) || angle < 0 || angle > 360) { return self; } // =
to use default if the user puts in strange values
+ else { height =3D angle; return self;}
+ };
+
+ self.separation =3D function(dist){ // changes the dist between the =
nodes of different depth
+ if (typeof dist =3D=3D=3D "undefined"){ return depthSeparation; }
+ else { depthSeparation =3D dist; return self;}
+ };
+
+ self.links =3D function (nodes) { // uses d3 native method to gene=
rate links. Done.
+ return d3.layout.tree().links(nodes);
+ };
+
+ // -- Custom method for laying out phylogeny tree in a linear fashion
+ self.nodes =3D function (d, i) {
+ var _nodes =3D hierarchy.call(self, d, i), // self is to f=
ind the depth of all the nodes, assumes root is passed in
+ nodes =3D [],
+ maxDepth =3D 0,
+ numLeaves =3D 0;
+
+ // changing from hierarchy's custom format for data to usable form=
at
+ _nodes.forEach(function (_node){
+ var node =3D _node.data;
+ node.depth =3D _node.depth;
+ maxDepth =3D node.depth > maxDepth ? node.depth : maxDepth; /=
/finding max depth of tree
+ nodes.push(node);
+ });
+ // counting the number of leaf nodes and assigning max depth to no=
des that do not have children to flush all the leave nodes
+ nodes.forEach(function(node){
+ if ( !node.children ) { //&& !node._children
+ numLeaves +=3D 1;
+ node.depth =3D maxDepth; // if a leaf has no child it woul=
d be assigned max depth
+ }
+ });
+
+ leafHeight =3D layoutMode =3D=3D=3D "Circular" ? height / numLeave=
s : leafHeight;
+ leafIndex =3D 0;
+ layout(nodes[0], maxDepth, leafHeight, null);
+
+ return nodes;
+ };
+
+
+ function layout (node, maxDepth, vertSeparation, parent) {
+ /**
+ * -- Function with side effect of adding x0, y0 to all child; tak=
e in the root as starting point
+ * assuming that the leave nodes would be sorted in presented ord=
er
+ * horizontal(y0) is calculated according to (=3D evo dis=
t X depth separation) from their parent
+ * vertical (x0) - if leave node: find its order in all o=
f the leave node =3D=3D=3D node.id, then multiply by verticalSeparation
+ * - if parent node: is place in the mid point al=
l of its children nodes
+ * -- The layout will first calculate the y0 field going towards t=
he leaves, and x0 when returning
+ */
+ var children =3D node.children,
+ sumChildVertSeparation =3D 0;
+
+ // calculation of node's dist from parents, going down.
+ var dist =3D node.dist || defaultDist;
+ dist =3D dist > 1 ? 1 : dist; // We constrain all dist to be l=
ess than one
+ node.dist =3D dist;
+ if (parent !=3D=3D null){
+ node.y0 =3D parent.y0 + dist * depthSeparation;
+ } else { //root node
+ node.y0 =3D maxTextWidth;
+ }
+
+
+ // if a node have no children, we will treat it as a leaf and star=
t laying it out first
+ if (!children) {
+ node.x0 =3D leafIndex++ * vertSeparation;
+ } else {
+ // if it has children, we will visit all its children and calc=
ulate its position from its children
+ children.forEach( function (child) {
+ child.parent =3D node;
+ sumChildVertSeparation +=3D layout(child, maxDepth, vertSe=
paration, node);
+ });
+ node.x0 =3D sumChildVertSeparation / children.length;
+ }
+
+ // adding properties to the newly created node
+ node.x =3D node.x0;
+ node.y =3D node.y0;
+ return node.x0;
+ }
+ return self;
+}
+
+
+/**
+ * -- PhyloTree Model --
+ */
+var PhyloTree =3D Visualization.extend({
+ defaults : {
+ layout: "Linear",
+ separation : 250, // px dist between nodes of different depth t=
o represent 1 evolutionary until
+ leafHeight: 18,
+ type : "phyloviz", // visualization type
+ title : "Title",
+ scaleFactor: 1,
+ translate: [0,0],
+ fontSize: 12, //fontSize of node label
+ selectedNode : null,
+ nodeAttrChangedTime : 0
+ },
+
+ root : {}, // Root has to be its own independent object because it is =
not part of the viz_config
+
+ toggle : function (d) {
+ /**
+ * Mechanism to expand or contract a single node. Expanded nodes h=
ave a children list, while for
+ * contracted nodes the list is stored in _children. Nodes with th=
eir children data stored in _children will not have their
+ * children rendered.
+ */
+ if(typeof d =3D=3D=3D "undefined") {return ;}
+ if (d.children ) {
+ d._children =3D d.children;
+ d.children =3D null;
+ } else {
+ d.children =3D d._children;
+ d._children =3D null;
+ }
+ },
+
+ toggleAll : function(d) {
+ /**
+ * Contracts the phylotree to a single node by repeatedly calling=
itself to place all the list
+ * of children under _children.
+ */
+ if (d.children && d.children.length !=3D=3D 0) {
+ d.children.forEach(this.toggleAll);
+ toggle(d);
+ }
+ },
+
+ getData : function (){
+ /**
+ * Return the data of the tree. Used for preserving state.
+ */
+ return this.root;
+ },
+
+ save: function() {
+ /**
+ * Overriding the default save mechanism to do some clean of circu=
lar reference of the
+ * phyloTree and to include phyloTree in the saved json
+ */
+ var root =3D this.root;
+ cleanTree(root);
+ this.set("root", root);
+
+ function cleanTree(node){
+ // we need to remove parent to delete circular reference
+ delete node.parent;
+
+ // removing unnecessary attributes
+ if (node._selected){ delete node._selected;}
+
+ node.children ? node.children.forEach(cleanTree) : 0;
+ node._children ? node._children.forEach(cleanTree) : 0;
+ }
+
+ var config =3D jQuery.extend(true, {}, this.attributes);
+ config["selectedNode"] =3D null;
+
+ show_message("Saving to Galaxy", "progress");
+
+ return $.ajax({
+ url: this.url(),
+ type: "POST",
+ dataType: "json",
+ data: {
+ vis_json: JSON.stringify(config)
+ },
+ success: function(res){
+ var viz_id =3D res.url.split("id=3D")[1].split("&")[0],
+ viz_url =3D "/phyloviz/visualization?id=3D" + viz_id;
+ window.history.pushState({}, "", viz_url + window.location=
.hash);
+ hide_modal();
+ }
+ });
+ }
+});
+
+
+
+/**
+ * -- Views --
+ */
+var PhylovizLayoutBase =3D Backbone.View.extend({
+ /**
+ * Stores the default variable for setting up the visualization
+ */
+ defaults : {
+ nodeRadius : 4.5 // radius of each node in the diagram
+ },
+
+
+ stdInit : function (options) {
+ /**
+ * Common initialization in layouts
+ */
+
+ var self =3D this;
+ self.model.on("change:separation change:leafHeight change:fontSize=
change:nodeAttrChangedTime", self.updateAndRender, self);
+
+ self.vis =3D options.vis;
+ self.i =3D 0;
+ self.maxDepth =3D -1; // stores the max depth of the tree
+
+ self.width =3D options.width;
+ self.height =3D options.height;
+ },
+
+
+ updateAndRender : function(source) {
+ /**
+ * Updates the visualization whenever there are changes in the ex=
pansion and contraction of nodes
+ * AND possibly when the tree is edited.
+ */
+ var vis =3D d3.select(".vis"),
+ self =3D this;
+ source =3D source || self.model.root;
+
+ self.renderNodes(source);
+ self.renderLinks(source);
+ self.addTooltips();
+ },
+
+
+ renderLinks : function(source) {
+ /**
+ * Renders the links for the visualization.
+ */
+ var self =3D this;
+ var diagonal =3D self.diagonal;
+ var duration =3D self.duration;
+ var layoutMode =3D self.layoutMode;
+ var link =3D self.vis.selectAll("g.completeLink")
+ .data(self.tree.links(self.nodes), function(d) { return d.targ=
et.id; });
+
+ var calcalateLinePos =3D function(d) {
+ d.pos0 =3D d.source.y0 + " " + d.source.x0; // position of t=
he source node <=3D> starting location of the line drawn
+ d.pos1 =3D d.source.y0 + " " + d.target.x0; // position where=
the line makes a right angle bend
+ d.pos2 =3D d.target.y0 + " " + d.target.x0; // point where=
the horizontal line becomes a dotted line
+ };
+
+ var linkEnter =3D link.enter().insert("svg:g","g.node")
+ .attr("class", "completeLink");
+
+
+ linkEnter.append("svg:path")
+ .attr("class", "link")
+ .attr("d", function(d) {
+ calcalateLinePos(d);
+ return "M " + d.pos0 + " L " + d.pos1;
+ });
+
+ var linkUpdate =3D link.transition().duration(500);
+
+ linkUpdate.select("path.link")
+ .attr("d", function(d) {
+ calcalateLinePos(d);
+ return "M " + d.pos0 + " L " + d.pos1 + " L " + d.pos2;
+ });
+
+ var linkExit =3D link.exit().remove();
+
+ },
+
+ // User Interaction methods below
+
+ selectNode : function(node){
+ /**
+ * Displays the information for editting
+ */
+ var self =3D this;
+ d3.selectAll("g.node")
+ .classed("selectedHighlight", function(d){
+ if (node.id =3D=3D=3D d.id){
+ if(node._selected) { // for de=3Dselecting node.
+ delete node._selected;
+ return false;
+ } else {
+ node._selected =3D true;
+ return true;
+ }
+ }
+ return false;
+ });
+
+ self.model.set("selectedNode", node);
+ $("#phyloVizSelectedNodeName").val(node.name);
+ $("#phyloVizSelectedNodeDist").val(node.dist);
+ $("#phyloVizSelectedNodeAnnotation").val(node.annotation || "");
+ },
+
+ addTooltips : function (){
+ /**
+ * Creates bootstrap tooltip for the visualization. Has to be cal=
led repeatedly due to newly generated
+ * enterNodes
+ */
+ $(".bs-tooltip").remove(); //clean up tooltip, just in case i=
ts listeners are removed by d3
+ $(".node")
+ .attr("data-original-title", function(){
+ var d =3D this.__data__,
+ annotation =3D d.annotation || "None" ;
+ return d ? (d.name ? d.name + "<br/>" : "") + "Dist: " + d=
.dist + " <br/>Annotation: " + annotation: "";
+ })
+ .tooltip({'placement':'top', 'trigger' : 'hover'});
+
+ }
+});
+
+
+
+
+var PhylovizLinearView =3D PhylovizLayoutBase.extend({
+ /**
+ * Linea layout class of Phyloviz, is responsible for rendering the no=
des
+ * calls PhyloTreeLayout to determine the positions of the nodes
+ */
+ initialize : function(options){
+ // Default values of linear layout
+ var self =3D this;
+ self.margins =3D options.margins;
+ self.layoutMode =3D "Linear";
+
+ self.stdInit(options);
+
+ self.layout();
+ self.updateAndRender(self.model.root);
+ },
+
+ layout : function() {
+ /**
+ * Creates the basic layout of a linear tree by precalculating fix=
ed values.
+ * One of calculations are also made here
+ */
+
+ var self =3D this;
+
+ self.tree =3D new PhyloTreeLayout().layoutMode("Linear");
+ self.diagonal =3D d3.svg.diagonal()
+ .projection(function(d) { return [d.y, d.x ]; });
+ },
+
+ renderNodes : function (source) {
+ /**
+ * Renders the nodes base on Linear layout.
+ */
+ var self =3D this,
+ fontSize =3D self.model.get("fontSize") + "px";
+
+ // assigning properties from models
+ self.tree.separation(self.model.get("separation")).leafHeight(self=
.model.get("leafHeight"));
+
+ var duration =3D 500,
+ nodes =3D self.tree.separation(self.model.get("separation")).n=
odes(self.model.root);
+
+ var node =3D self.vis.selectAll("g.node")
+ .data(nodes, function(d) { return d.name + d.id || (d.id =3D +=
+self.i); });
+
+ // These variables has to be passed into update links which are in=
the base methods
+ self.nodes =3D nodes;
+ self.duration =3D duration;
+
+ // ------- D3 ENTRY --------
+ // Enter any new nodes at the parent's previous position.
+ var nodeEnter =3D node.enter().append("svg:g")
+ .attr("class", "node")
+ .on("dblclick", function(){ d3.event.stopPropagation(); })
+ .on("click", function(d) {
+ if (d3.event.altKey) {
+ self.selectNode(d); // display info if alt is p=
ressed
+ } else {
+ if(d.children && d.children.length =3D=3D=3D 0){ retur=
n;} // there is no need to toggle leaves
+ self.model.toggle(d); // contract/expand nodes at da=
ta level
+ self.updateAndRender(d); // re-render the tree
+ }
+ });
+
+ nodeEnter.attr("transform", function(d) { return "translate(" + so=
urce.y0 + "," + source.x0 + ")"; });
+
+ nodeEnter.append("svg:circle")
+ .attr("r", 1e-6)
+ .style("fill", function(d) { return d._children ? "lightsteelb=
lue" : "#fff"; });
+
+ nodeEnter.append("svg:text")
+ .attr("class", "nodeLabel")
+ .attr("x", function(d) { return d.children || d._children ? -1=
0 : 10; })
+ .attr("dy", ".35em")
+ .attr("text-anchor", function(d) { return d.children || d._chi=
ldren ? "end" : "start"; })
+ .style("fill-opacity", 1e-6);
+
+ // ------- D3 TRANSITION --------
+ // Transition nodes to their new position.
+ var nodeUpdate =3D node.transition()
+ .duration(duration);
+
+ nodeUpdate.attr("transform", function(d) {
+ return "translate(" + d.y + "," + d.x + ")"; });
+
+ nodeUpdate.select("circle")
+ .attr("r", self.defaults.nodeRadius)
+ .style("fill", function(d) { return d._children ? "lightsteelb=
lue" : "#fff"; });
+
+ nodeUpdate.select("text")
+ .style("fill-opacity", 1)
+ .style("font-size", fontSize)
+ .text(function(d) { return d.name; });
+
+ // ------- D3 EXIT --------
+ // Transition exiting nodes to the parent's new position.
+ var nodeExit =3Dnode.exit().transition()
+ .duration(duration)
+ .remove();
+
+ nodeExit.select("circle")
+ .attr("r", 1e-6);
+
+ nodeExit.select("text")
+ .style("fill-opacity", 1e-6);
+
+ // Stash the old positions for transition.
+ nodes.forEach(function(d) {
+ d.x0 =3D d.x; // we need the x0, y0 for parents with children
+ d.y0 =3D d.y;
+ });
+ }
+
+});
+
+var PhylovizView =3D Backbone.View.extend({
+
+ className: 'phyloviz',
+
+ initialize: function(options) {
+ var self =3D this;
+ // -- Default values of the vis
+ self.MIN_SCALE =3D 0.05; //for zooming
+ self.MAX_SCALE =3D 5;
+ self.MAX_DISPLACEMENT =3D 500;
+ self.margins =3D [10, 60, 10, 80];
+
+ self.width =3D $("#PhyloViz").width();
+ self.height =3D $("#PhyloViz").height();
+ self.radius =3D self.width;
+ self.data =3D options.data;
+
+ // -- Events Phyloviz view responses to
+ $(window).resize(function(){
+ self.width =3D $("#PhyloViz").width();
+ self.height =3D $("#PhyloViz").height();
+ self.render();
+ });
+
+ // -- Create phyloTree model
+ self.phyloTree =3D new PhyloTree(options.config);
+ self.phyloTree.root =3D self.data;
+
+ // -- Set up UI functions of main view
+ self.zoomFunc =3D d3.behavior.zoom().scaleExtent([self.MIN_SCALE, =
self.MAX_SCALE]);
+ self.zoomFunc.translate(self.phyloTree.get("translate"));
+ self.zoomFunc.scale(self.phyloTree.get("scaleFactor"));
+
+ // -- set up header buttons, search and settings menu
+ self.navMenu =3D new HeaderButtons(self);
+ self.settingsMenu =3D new SettingsMenu({phyloTree : self.phyloTree=
});
+ self.nodeSelectionView =3D new NodeSelectionView({phyloTree : self=
.phyloTree});
+ self.search =3D new PhyloVizSearch();
+
+
+ setTimeout(function(){ // using settimeout to call the zoomAn=
dPan function according to the stored attributes in viz_config
+ self.zoomAndPan();
+ }, 1000);
+ },
+
+ render: function(){
+ // -- Creating helper function for vis. --
+ var self =3D this;
+ $("#PhyloViz").empty();
+
+ // -- Layout viz. --
+ self.mainSVG =3D d3.select("#PhyloViz").append("svg:svg")
+ .attr("width", self.width)
+ .attr("height", self.height)
+ .attr("pointer-events", "all")
+ .call(self.zoomFunc.on("zoom", function(){
+ self.zoomAndPan();
+ }));
+
+ self.boundingRect =3D self.mainSVG.append("svg:rect")
+ .attr("class", "boundingRect")
+ .attr("width", self.width)
+ .attr("height", self.height)
+ .attr("stroke", "black")
+ .attr("fill", "white");
+
+ self.vis =3D self.mainSVG
+ .append("svg:g")
+ .attr("class", "vis");
+
+ self.layoutOptions =3D {
+ model : self.phyloTree,
+ width : self.width,
+ height : self.height,
+ vis: self.vis,
+ margins: self.margins
+ };
+
+ // -- Creating Title
+ $("#title").text("Phylogenetic Tree from " + self.phyloTree.get("t=
itle") + ":");
+
+ // -- Create Linear view instance --
+ var linearView =3D new PhylovizLinearView(self.layoutOptions)
+ },
+
+ zoomAndPan : function(event){
+ /**
+ * 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 an=
d keeping states in model
+ */
+ if (typeof event !=3D=3D "undefined") {
+ var zoomParams =3D event.zoom,
+ translateParams =3D event.translate;
+ }
+
+ var self =3D this,
+ scaleFactor =3D self.zoomFunc.scale(),
+ translationCoor =3D self.zoomFunc.translate(),
+ zoomStatement =3D "",
+ translateStatement =3D "";
+
+ // Do manual scaling.
+ switch (zoomParams) {
+ case "reset":
+ scaleFactor =3D 1.0;
+ translationCoor =3D [0,0]; break;
+ case "+":
+ scaleFactor *=3D 1.1; break;
+ case "-":
+ scaleFactor *=3D 0.9; break;
+ default:
+ if (typeof zoomParams =3D=3D=3D "number") {
+ scaleFactor =3D zoomParams;
+ } else if (d3.event !=3D=3D null) {
+ scaleFactor =3D d3.event.scale;
+ }
+ }
+ if (scaleFactor < self.MIN_SCALE || scaleFactor > self.MAX_SCALE) =
{ return;}
+ self.zoomFunc.scale(scaleFactor); //update scale Factor
+ zoomStatement =3D "translate(" + self.margins[3] + "," + self.mar=
gins[0] + ")" +
+ " scale(" + scaleFactor + ")";
+
+ // Do manual translation.
+ if( d3.event !=3D=3D null) {
+ translateStatement =3D "translate(" + d3.event.translate + ")";
+ } else {
+ if(typeof translateParams !=3D=3D "undefined") {
+ var x =3D translateParams.split(",")[0];
+ var y =3D translateParams.split(",")[1];
+ if (!isNaN(x) && !isNaN(y)){
+ translationCoor =3D [translationCoor[0] + parseFloat(x=
), translationCoor[1] + parseFloat(y)];
+ }
+ }
+ self.zoomFunc.translate(translationCoor); // update zoomFunc
+ translateStatement =3D "translate(" + translationCoor + ")";
+ }
+
+ self.phyloTree.set("scaleFactor", scaleFactor);
+ self.phyloTree.set("translate", translationCoor);
+ self.vis.attr("transform", translateStatement + zoomStatement); //=
refers to the view that we are actually zooming
+ },
+
+
+ reloadViz : function() {
+ /**
+ * Primes the Ajax URL to load another Nexus tree
+ */
+ var self =3D this,
+ treeIndex =3D $("#phylovizNexSelector :selected").val(),
+ dataset_id =3D self.phyloTree.get("dataset_id"),
+ url =3D "phyloviz/getJsonData?dataset_id=3D" + dataset_id + "&=
treeIndex=3D" + String(treeIndex);
+ $.getJSON(url, function(packedJson){
+ window.initPhyloViz(packedJson.data, packedJson.config);
+ });
+ }
+});
+
+
+var HeaderButtons =3D Backbone.View.extend({
+
+ initialize : function(phylovizView){
+ var self =3D this;
+ self.phylovizView =3D phylovizView;
+
+ // Clean up code - if the class initialized more than once
+ $("#panelHeaderRightBtns").empty();
+ $("#phyloVizNavBtns").empty();
+ $("#phylovizNexSelector").off();
+
+ self.initNavBtns();
+ self.initRightHeaderBtns();
+
+ // Initial a tree selector in the case of nexus
+ $("#phylovizNexSelector").off().on("change", function() {self.phy=
lovizView.reloadViz();} );
+
+ },
+
+ initRightHeaderBtns : function(){
+ var self =3D this;
+
+ rightMenu =3D create_icon_buttons_menu([
+ { icon_class: 'gear', title: 'PhyloViz Settings', on_click: fu=
nction(){
+ $("#SettingsMenu").show();
+ self.settingsMenu.updateUI();
+ } },
+ { icon_class: 'disk', title: 'Save visualization', on_click: f=
unction() {
+ var nexSelected =3D $("#phylovizNexSelector option:selecte=
d").text();
+ if(nexSelected) {
+ self.phylovizView.phyloTree.set("title", nexSelected);
+ }
+ self.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');
+ // https://docs.google.com/document/d/1AXFoJgEpxr21H3LICRs=
3EyMe1B1X_KFPouzIgrCz3zk/edit
+ } }
+ ],
+ {
+ tooltip_config: { placement: 'bottom' }
+ });
+ $("#panelHeaderRightBtns").append(rightMenu.$el);
+ },
+
+ initNavBtns: function() {
+ var self =3D this,
+ navMenu =3D create_icon_buttons_menu([
+ { icon_class: 'zoom-in', title: 'Zoom in', on_click: funct=
ion() {
+ self.phylovizView.zoomAndPan({ zoom : "+"});
+ } },
+ { icon_class: 'zoom-out', title: 'Zoom out', on_click: fun=
ction() {
+ self.phylovizView.zoomAndPan({ zoom : "-"});
+ } },
+ { icon_class: 'arrow-circle', title: 'Reset Zoom/Pan', on_=
click: function() {
+ self.phylovizView.zoomAndPan({ zoom : "reset"});
+ } }
+ ],
+ {
+ tooltip_config: { placement: 'bottom' }
+ });
+ $("#phyloVizNavBtns").append(navMenu.$el);
+ }
+});
+
+
+var SettingsMenu =3D UserMenuBase.extend({
+
+ className: 'Settings',
+
+ initialize: function(options){
+ // settings needs to directly interact with the phyloviz model so =
it will get access to it.
+ var self =3D this;
+ self.phyloTree =3D options.phyloTree;
+ self.el =3D $("#SettingsMenu");
+ self.inputs =3D {
+ separation : $("#phyloVizTreeSeparation"),
+ leafHeight : $("#phyloVizTreeLeafHeight"),
+ fontSize : $("#phyloVizTreeFontSize")
+ };
+
+ //init all buttons of settings
+ $("#settingsCloseBtn").off().on("click", function() { self.el.hide=
(); });
+ $("#phylovizResetSettingsBtn").off().on("click", function() { self=
.resetToDefaults(); });
+ $("#phylovizApplySettingsBtn").off().on("click", function() { self=
.apply(); });
+ },
+
+ apply : function(){
+ /**
+ * Applying user values to phylotree model.
+ */
+ var self =3D this;
+ 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){
+ self.phyloTree.set(key, $input.val());
+ });
+ },
+ updateUI : function(){
+ /**
+ * Called to update the values input to that stored in the model
+ */
+ var self =3D this;
+ $.each(self.inputs, function(key, $input){
+ $input.val(self.phyloTree.get(key));
+ });
+ },
+ resetToDefaults : function(){
+ /**
+ * Resets the value of the phyloTree model to its default
+ */
+ $(".bs-tooltip").remove(); // just in case the tool tip was n=
ot removed
+ var self =3D this;
+ $.each(self.phyloTree.defaults, function(key, value) {
+ self.phyloTree.set(key, value);
+ });
+ self.updateUI();
+ },
+
+ render: function(){
+
+ }
+
+});
+
+
+var NodeSelectionView =3D UserMenuBase.extend({
+ /**
+ * View for inspecting node properties and editing them
+ */
+ className: 'Settings',
+
+ initialize : function (options){
+ var self =3D this;
+ self.el =3D $("#nodeSelectionView");
+ self.phyloTree =3D options.phyloTree;
+
+ self.UI =3D {
+ enableEdit : $('#phylovizEditNodesCheck'),
+ saveChanges : $('#phylovizNodeSaveChanges'),
+ cancelChanges : $("#phylovizNodeCancelChanges"),
+ name : $("#phyloVizSelectedNodeName"),
+ dist : $("#phyloVizSelectedNodeDist"),
+ annotation : $("#phyloVizSelectedNodeAnnotation")
+ };
+
+ self.valuesOfConcern =3D {
+ name : null,
+ dist : null,
+ annotation : null
+ }; // temporarily stores the values in case user change their mind
+
+ //init UI buttons
+ $("#nodeSelCloseBtn").off().on("click", function() { self.el.hide(=
); });
+ self.UI.saveChanges.off().on("click", function(){ self.updateNodes=
(); });
+ self.UI.cancelChanges.off().on("click", function(){ self.cancelCha=
nges(); });
+
+ (function ($) {
+ // extending jquery fxn for enabling and disabling nodes.
+ $.fn.enable =3D function (isEnabled) {
+ return $(this).each(function () {
+ if(isEnabled){
+ $(this).removeAttr('disabled');
+ } else {
+ $(this).attr('disabled', 'disabled');
+ }
+ });
+ };
+ })(jQuery);
+
+ self.UI.enableEdit.off().on("click", function () {
+ self.toggleUI();
+ });
+ },
+
+ toggleUI : function(){
+ /**
+ * For turning on and off the child elements
+ */
+ var self =3D this,
+ checked =3D self.UI.enableEdit.is(':checked');
+
+ !checked ? self.cancelChanges() : "";
+
+ $.each(self.valuesOfConcern, function(key, value) {
+ self.UI[key].enable(checked);
+ });
+ if(checked){
+ self.UI.saveChanges.show();
+ self.UI.cancelChanges.show();
+ } else {
+ self.UI.saveChanges.hide();
+ self.UI.cancelChanges.hide();
+ }
+
+ },
+
+ cancelChanges : function() {
+ /**
+ * Reverting to previous values in case user change their minds
+ */
+ var self =3D this,
+ node =3D self.phyloTree.get("selectedNode");
+ if (node){
+ $.each(self.valuesOfConcern, function(key, value) {
+ self.UI[key].val(node[key]);
+ });
+ }
+ },
+
+ updateNodes : function (){
+ /**
+ * Changing the data in the underlying tree with user-specified va=
lues
+ */
+ var self =3D this,
+ node =3D self.phyloTree.get("selectedNode");
+ if (node){
+ if (!self.isAcceptableValue(self.UI.dist, 0, 1) ||
+ self.hasIllegalJsonCharacters(self.UI.name) ||
+ self.hasIllegalJsonCharacters(self.UI.annotation) ) {
+ return;
+ }
+ $.each(self.valuesOfConcern, function(key, value) {
+ (node[key]) =3D self.UI[key].val();
+ });
+ self.phyloTree.set("nodeAttrChangedTime", new Date());
+ } else {
+ alert("No node selected");
+ }
+ }
+
+
+});
+
+
+
+var PhyloVizSearch =3D UserMenuBase.extend({
+ /**
+ * Initializes the search panel on phyloviz and handles its user inter=
action
+ * It allows user to search the entire free based on some qualifer, li=
ke dist <=3D val.
+ */
+ initialize : function () {
+ var self =3D this;
+
+ $("#phyloVizSearchBtn").on("click", function(){
+ var searchTerm =3D $("#phyloVizSearchTerm"),
+ searchConditionVal =3D $("#phyloVizSearchCondition").val()=
.split("-"),
+ attr =3D searchConditionVal[0],
+ condition =3D searchConditionVal[1];
+ self.hasIllegalJsonCharacters(searchTerm);
+
+ if (attr =3D=3D=3D "dist"){
+ self.isAcceptableValue(searchTerm, 0, 1);
+ }
+ self.searchTree(attr, condition, searchTerm.val());
+ });
+ },
+
+ searchTree : function (attr, condition, val){
+ /**
+ * Searches the entire tree and will highlight the nodes that matc=
h the condition in green
+ */
+ d3.selectAll("g.node")
+ .classed("searchHighlight", function(d){
+ var attrVal =3D d[attr];
+ if (typeof attrVal !=3D=3D "undefined" && attrVal !=3D=3D =
null){
+ if (attr =3D=3D=3D "dist"){
+ switch (condition) {
+ case "greaterEqual":
+ return attrVal >=3D +val;
+ case "lesserEqual":
+ return attrVal <=3D +val;
+ default:
+ return;
+ }
+
+ } else if (attr =3D=3D=3D "name" || attr =3D=3D=3D "an=
notation") {
+ return attrVal.toLowerCase().indexOf(val.toLowerCa=
se()) !=3D=3D -1;
+ }
+ }
+ });
+ }
+});
\ No newline at end of file
diff -r b1f2c51d6bd8d8b1aecce8f62304cc2df278ccec -r f6d9557b6d77bde1c8049ba=
ffb65374729d51b89 templates/root/history.mako
--- a/templates/root/history.mako
+++ b/templates/root/history.mako
@@ -272,6 +272,17 @@
}
=20
init_trackster_links();
+
+ function init_phyloviz_links() {
+ // PhyloViz links
+ // Add to trackster browser functionality
+ $(".phyloviz-add").live("click", function() {
+ var dataset =3D this,
+ dataset_jquery =3D $(this);
+ window.parent.location =3D dataset_jquery.attr("new-url");
+ });
+ }
+ init_phyloviz_links();
=20
// History rename functionality.
async_save_text("history-name-container", "history-name", "${h.url_for=
( controller=3D"/history", action=3D"rename_async", id=3Dtrans.security.enc=
ode_id(history.id) )}", "new_name", 18);
diff -r b1f2c51d6bd8d8b1aecce8f62304cc2df278ccec -r f6d9557b6d77bde1c8049ba=
ffb65374729d51b89 templates/root/history_common.mako
--- a/templates/root/history_common.mako
+++ b/templates/root/history_common.mako
@@ -29,6 +29,9 @@
## Render the dataset `data` as history item, using `hid` as the displayed=
id
<%def name=3D"render_dataset( data, hid, show_deleted_on_refresh =3D False=
, for_editing =3D True, display_structured =3D False )"><%
+
+ from galaxy.datatypes.xml import Phyloxml
+ from galaxy.datatypes.data import Newick, Nexus
dataset_id =3D trans.security.encode_id( data.id )
=20
if data.state in ['no state','',None]:
@@ -230,6 +233,14 @@
action-url=3D"${h.url_for( controller=3D't=
racks', action=3D'browser', dataset_id=3Ddataset_id)}"
new-url=3D"${h.url_for( controller=3D'trac=
ks', action=3D'index', dataset_id=3Ddataset_id, default_dbkey=3Ddata.dbkey)=
}" title=3D"View in Trackster"></a>
%endif
+ <%
+ isPhylogenyData =3D isinstance(data.datatype, =
(Phyloxml, Nexus, Newick))
+ %>
+ %if isPhylogenyData:
+ <a href=3D"javascript:void(0)" class=3D"i=
con-button chart_curve phyloviz-add"
+ action-url=3D"${h.url_for( controller=
=3D'phyloviz', action=3D'-', dataset_id=3Ddataset_id)}"
+ new-url=3D"${h.url_for( controller=3D'p=
hyloviz', action=3D'index', dataset_id=3Ddataset_id)}" title=3D"View in Phy=
loviz"></a>
+ %endif
%if trans.user:
%if not display_structured:
<div style=3D"float: right">
diff -r b1f2c51d6bd8d8b1aecce8f62304cc2df278ccec -r f6d9557b6d77bde1c8049ba=
ffb65374729d51b89 templates/visualization/phyloviz.mako
--- /dev/null
+++ b/templates/visualization/phyloviz.mako
@@ -0,0 +1,320 @@
+<%inherit file=3D"/webapps/galaxy/base_panels.mako"/>
+##
+<%def name=3D"init()">
+ <%
+ self.has_left_panel=3DFalse
+ self.has_right_panel=3DFalse
+ self.active_view=3D"visualization"
+ self.message_box_visible=3DFalse
+ %>
+</%def>
+
+<%def name=3D"stylesheets()">
+ ${parent.stylesheets()}
+ <style>
+
+ .node circle {
+ cursor: pointer;
+ fill: #fff;
+ stroke: steelblue;
+ stroke-width: 1.5px;
+ }
+
+ .node.searchHighlight circle {
+ stroke-width: 3px;
+ stroke: #7adc26;
+ }
+
+ .node.selectedHighlight circle {
+ stroke-width: 3px;
+ stroke: #dc143c;
+ }
+
+ path.link {
+ fill: none;
+ stroke: #B5BBFF;
+ stroke-width: 4.0px;
+ }
+
+
+ div #phyloVizNavContainer{
+ text-align: center;
+ width: 100%;
+ height: 0px;
+ }
+
+ div #phyloVizNav{
+ font-weight: bold;
+ display: inline-block;
+ background: transparent;
+ top: -2em;
+ position: relative;
+ }
+
+ div .navControl{
+ float: left;
+ }
+
+ div#FloatingMenu {
+ left: 0;
+ top: 15%;
+ width:20%;
+ z-index:100;
+ padding: 5px;
+
+ }
+
+ div#SettingsMenu {
+ width: 25%;
+ top: 350px;
+
+ }
+
+ div#nodeSelectionView {
+ width: 25%;
+ top:70px;
+ }
+
+ .Panel {
+ right: 0%;
+ z-index: 101;
+ position: fixed;
+
+ ## Borrowed from galaxy modal_dialogues
+ background-color: white;
+ border: 1px solid #999;
+ border: 1px solid rgba(0, 0, 0, 0.3);
+ -webkit-border-radius: 6px;
+ -moz-border-radius: 6px;
+ border-radius: 6px;
+ -webkit-border-radius: 6px;
+ -moz-border-radius: 6px;
+ border-radius: 6px;
+ -webkit-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3);
+ -moz-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3);
+ box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3);
+ -webkit-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3);
+ -moz-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3);
+ box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3);
+ -webkit-background-clip: padding-box;
+ -moz-background-clip: padding-box;
+ background-clip: padding-box;
+ -webkit-background-clip: padding-box;
+ -moz-background-clip: padding-box;
+ background-clip: padding-box;
+ }
+
+ span.PhylovizCloseBtn{
+ cursor: pointer;
+ float : right;
+ }
+
+ #PhyloViz{
+ width: 100%;
+ height: 95%;
+ }
+
+ h2.PhyloVizMenuTitle{
+ color: white;
+ }
+
+ ## Settings Menu
+ .SettingMenuRows{
+ margin: 2px 0 2px 0;
+ }
+
+
+ ## Helper Styles
+ .PhyloVizFloatLeft{
+ float : left;
+ }
+ .icon-button.zoom-in,.icon-button.zoom-out{display:inline-block;he=
ight:16px;width:16px;margin-bottom:-3px;cursor:pointer;}
+ .icon-button.zoom-out{background:transparent url(../images/fugue/m=
agnifier-zoom-out.png) center center no-repeat;}
+ .icon-button.zoom-in{margin-left:10px;background:transparent url(.=
./images/fugue/magnifier-zoom.png) center center no-repeat;}
+
+ </style>
+</%def>
+
+
+<%def name=3D"javascripts()">
+ ${parent.javascripts()}
+ ${h.js( "galaxy.panels", "libs/d3", "mvc/data", "viz/visualization", "=
viz/phyloviz")}
+</%def>
+
+
+
+<%def name=3D"center_panel()">
+
+ <div class=3D"unified-panel-header" unselectable=3D"on">
+ <div class=3D"unified-panel-header-inner">
+ <div style=3D"float:left;" id=3D"title"></div>
+ <div style=3D"float:right;" id=3D"panelHeaderRightBtns"></div>
+ </div>
+ <div style=3D"clear: both"></div>
+ </div>
+
+
+ <div id=3D"phyloVizNavContainer">
+ <div id=3D"phyloVizNav">
+ %if config["ext"] =3D=3D "nex" and not config["saved_visualiza=
tion"]:
+ <div id =3D "phylovizNexInfo" class=3D"navControl">
+ <p>Select a tree to view:
+ <select id=3D"phylovizNexSelector">
+ % for tree, index in config["trees"]:
+ <option value=3D"${index}">${tree}</option>
+ % endfor
+ </select>
+ </p>
+ </div>
+ %endif
+ <div id=3D"phyloVizNavBtns" class=3D"navControl">
+ </div>
+ <div class=3D"navControl">
+ <p> | Alt+click to select nodes</p>
+ </div>
+
+
+ </div>
+
+ </div>
+
+ ## Node Selection Menu
+ <div id=3D"nodeSelectionView" class=3D"Panel">
+ <div class=3D"modal-header">
+ <h3 class=3D"PhyloVizMenuTitle">Search / Edit Nodes :
+ <span class=3D"PhylovizCloseBtn" id=3D"nodeSelCloseBtn"> X=
</span>
+ </h3>
+ </div>
+
+ <div class=3D"modal-body">
+
+ <div class=3D"SettingMenuRows">
+ Search for nodes with:
+ <select id=3D"phyloVizSearchCondition" style=3D"width: 55%=
">
+ <option value=3D"name-containing">Name (containing)</o=
ption>
+ <option value=3D"annotation-containing">Annotation (co=
ntaining)</option>
+ <option value=3D"dist-greaterEqual">Distance (>=3D)</o=
ption>
+ <option value=3D"dist-lesserEqual">Distance (<=3D)</op=
tion>
+ </select>
+ <input type=3D"text" id=3D"phyloVizSearchTerm" value=3D"N=
one" size=3D"15" displayLabel=3D"Distance">
+
+ <div class=3D"SettingMenuRows" style=3D"text-align: center=
;">
+ <button id=3D"phyloVizSearchBtn" > Search! </button>
+ </div>
+ </div>
+
+ <br/>
+
+ <div class=3D"SettingMenuRows">
+ Name: <input type=3D"text" id=3D"phyloVizSelectedNodeName"=
value=3D"None" size=3D"15" disabled=3D"disabled" >
+ </div>
+ <div class=3D"SettingMenuRows">
+ Dist: <input type=3D"text" id=3D"phyloVizSelectedNodeDist"=
value=3D"None" size=3D"15" disabled=3D"disabled" displayLabel=3D"Distance">
+ </div>
+ <div class=3D"SettingMenuRows">
+ Annotation:
+ <textarea id=3D"phyloVizSelectedNodeAnnotation" disabled=
=3D"disabled" ></textarea>
+ </div>
+ <div class=3D"SettingMenuRows">
+ Edit: <input type=3D"checkbox" id=3D"phylovizEditNodesChec=
k" value=3D"You can put custom annotations here and it will be saved">
+ <button id=3D"phylovizNodeSaveChanges" style=3D"display: n=
one;"> Save edits</button>
+ <button id=3D"phylovizNodeCancelChanges" style=3D"display:=
none;"> Cancel</button>
+ </div>
+ </div>
+ </div>
+
+ ## Settings Menus
+ <div id=3D"SettingsMenu" class=3D"Panel">
+ <div class=3D"modal-header">
+ <h3 class=3D"PhyloVizMenuTitle">Phyloviz Settings:
+ <span class=3D"PhylovizCloseBtn" id=3D"settingsCloseBtn"> =
X </span>
+ </h3>
+ </div>
+ <div class=3D"modal-body">
+ <div class=3D"SettingMenuRows">
+ Phylogenetic Spacing (px per unit): <input id=3D"phyloVizT=
reeSeparation" type=3D"text" value=3D"250" size=3D"10" displayLabel=3D"Phyl=
ogenetic Separation"> (50-2500)
+ </div>
+ <div class=3D"SettingMenuRows">
+ Vertical Spacing (px): <input type=3D"text" id=3D"phyloViz=
TreeLeafHeight" value=3D"18" size=3D"10" displayLabel=3D"Vertical Spacing">=
(5-30)
+ </div>
+ <div class=3D"SettingMenuRows">
+ Font Size (px): <input type=3D"text" id=3D"phyloVizTreeFon=
tSize" value=3D"12" size=3D"4" displayLabel=3D"Font Size"> (5-20)
+ </div>
+
+ </div>
+ <div class=3D"modal-footer">
+ <button id=3D"phylovizResetSettingsBtn" class=3D"PhyloVizFloat=
Left" > Reset </button>
+ <button id=3D"phylovizApplySettingsBtn" class=3D"PhyloVizFloat=
Right" > Apply </button>
+ </div>
+ </div>
+
+
+
+
+
+
+ <div class=3D"Panel" id=3D"FloatingMenu" style=3D"display: None;">
+
+ <h2>PhyloViz (<a onclick=3D"displayHelp()" href=3D"javascript:void=
(0);">?</a>)</h2>
+ <div style=3D"display: none;">
+ <h2>Summary of Interactions and Functions:</h2>
+ <div class=3D"hint">1. Expansion of Nodes: click or option-cli=
ck to expand or collapse</div>
+ <div class=3D"hint">2. Zooming and translation: mousewheel, bu=
ttons, click and drag, double click. Reset</div>
+ <div class=3D"hint">3. Tooltip: Displays "Name and Size" on mo=
useOver on nodes</div>
+ <div class=3D"hint">4. Minimap: Currently displays an exact bu=
t scaled down replicate of the tree, orange bounding box is correct for lin=
ear only<br/>
+ Can be switched on or off</div>
+ <div class=3D"hint">5. Changing Layouts: Able to change betwee=
n circular and linear layouts.</div>
+
+ </div>
+
+ <h5>Scaling & Rotation:</h5>
+ <button id=3D"phylovizZoomInBtn" class=3D"" > + </button>
+ <button id=3D"phylovizZoomOutBtn" class=3D"" > - </button>
+
+
+ <h5>Translation:</h5>
+ <button id=3D"phylovizTranslateUpBtn" > Up </button>
+ <button id=3D"phylovizTranslateDownBtn" > Down </button>
+ <br/>
+ <button id=3D"phylovizTranslateLeftBtn" > Left </button>
+ <button id=3D"phylovizTranslateRightBtn" > Right </button>
+
+
+
+ <h5>Others:</h5>
+ <button id=3D"phylovizResetBtn" > Reset Zoom/Translate </button>
+ <button id=3D"phylovizSaveBtn" > Save vizualization </button>
+ <button id=3D"phylovizOpenSettingsBtn" > Settings </button>
+ </div>
+
+ <div id=3D"PhyloViz" >
+ </div>
+
+ <script type=3D"text/javascript">
+
+ function initPhyloViz(data, config) {
+ var phyloviz;
+
+ // -- Initialization code |-->
+ phyloviz =3D new PhylovizView({
+ data: data,
+ layout : "Linear",
+ config : config
+ });
+
+ // -- Render viz. --
+ phyloviz.render();
+
+ }
+
+ $(function firstVizLoad(){ // calls when viz is loaded for t=
he first time
+ var config =3D JSON.parse( '${ h.to_json_string( config )}');
+ var data =3D JSON.parse('${h.to_json_string(data)}');
+ initPhyloViz(data, config);
+ });
+
+ </script>
+
+</%def>
+
+
diff -r b1f2c51d6bd8d8b1aecce8f62304cc2df278ccec -r f6d9557b6d77bde1c8049ba=
ffb65374729d51b89 test-data/visualization/phyloviz/1_nexus.nex
--- /dev/null
+++ b/test-data/visualization/phyloviz/1_nexus.nex
@@ -0,0 +1,87 @@
+#NEXUS
+
+[!This data set was downloaded from TreeBASE, a relational database of phy=
logenetic knowledge. TreeBASE has been supported by the NSF, Harvard Univer=
sity, Yale University, SDSC and UC Davis. Please do not remove this acknowl=
edgment from the Nexus file.
+
+
+Generated on June 12, 2012; 23:00 GMT
+
+TreeBASE (cc) 1994-2008
+
+Study reference:
+Olariaga I., Grebenc T., Salcedo I., & Mart=C3=ADn M.P. 2012. Two new spec=
ies of Hydnum
+with ovoid basidiospores: H. ovoideisporum and H. vesterholtii. Mycologia,=
.
+
+TreeBASE Study URI: http://purl.org/phylo/treebase/phylows/study/TB2:S128=
31]
+
+BEGIN TREES;
+ TITLE Hydnum_ITS_result;
+ LINK TAXA =3D Taxa1;
+ TRANSLATE
+ 1 Hydnum_aff_ellipsosporum_RUFHYD1_AJ535304,
+ 2 Hydnum_albidum_ALB_AY817135,
+ 3 Hydnum_albidum_ALBHYD1_AJ534974,
+ 4 Hydnum_albomagnum_ALM_DQ218305,
+ 5 Hydnum_ellipsosporum_ELL_AY817138,
+ 6 Hydnum_ellipsosporum_RUFHYD8_AJ547882,
+ 7 Hydnum_ovoidisporum_12317BIOFungi,
+ 8 Hydnum_ovoidisporum_12683BIOFungi,
+ 9 Hydnum_ovoidisporum_12902BIOFungi,
+ 10 Hydnum_ovoidisporum_14130BIOFungi,
+ 11 Hydnum_repandum_RE1_REP1_AJ889978,
+ 12 Hydnum_repandum_RE1_REP2_AJ889949,
+ 13 Hydnum_repandum_RE1_REP3_AY817136,
+ 14 Hydnum_repandum_RE1_REP6_UDB000025,
+ 15 Hydnum_repandum_RE1_REP7_UDB000096,
+ 16 Hydnum_repandum_RE1_REP8_UDB001479,
+ 17 Hydnum_repandum_RE1_REPHYD10_AJ547888,
+ 18 Hydnum_repandum_RE1_REPHYD11_AJ547886,
+ 19 Hydnum_repandum_RE1_REPHYD1_AJ547871,
+ 20 Hydnum_repandum_RE1_REPHYD3_AJ547874,
+ 21 Hydnum_repandum_RE1_REPHYD4_AJ547876,
+ 22 Hydnum_repandum_RE1_REPHYD5_AJ547875,
+ 23 Hydnum_repandum_RE1_REPHYD6_AJ547877,
+ 24 Hydnum_repandum_RE1_REPHYD7_AJ547878,
+ 25 Hydnum_repandum_RE1_REPHYD8_AJ547881,
+ 26 Hydnum_repandum_RE1_REPHYD9_AJ547883,
+ 27 Hydnum_repandum_RE1_RUFHYD10_AJ547866,
+ 28 Hydnum_repandum_RE1_RUFHYD11_AJ547889,
+ 29 Hydnum_repandum_RE1_RUFHYD9_AJ535305,
+ 30 Hydnum_rufescens_RU1_RUFHYD5_AJ547869,
+ 31 Hydnum_rufescens_RU1_RUFHYD6_AJ547884,
+ 32 Hydnum_rufescens_RU1_RUFHYD7_AJ547870,
+ 33 Hydnum_rufescens_RU2_REP5_DQ367902,
+ 34 Hydnum_rufescens_RU2_RUFHYD2_AJ535301,
+ 35 Hydnum_rufescens_RU3_12901BIOFungi,
+ 36 Hydnum_rufescens_RU3_REP4_DQ218306,
+ 37 Hydnum_rufescens_RU3_RUFHYD3_AJ535303,
+ 38 Hydnum_rufescens_RU3_RUFHYD4_AJ535302,
+ 39 Hydnum_rufescens_RU4_RUFHYD12_AJ839969,
+ 40 Hydnum_rufescens_RU4_RUFHYD16_AJ547868,
+ 41 Hydnum_rufescens_RU4_RUFHYD17_AJ547885,
+ 42 Hydnum_rufescens_RU4_UMB1_DQ367903,
+ 43 Hydnum_rufescens_RU5_12760BIOFungi,
+ 44 Hydnum_rufescens_RU5_ALBHYD2_AJ534975,
+ 45 Hydnum_rufescens_RU5_RUF2_DQ658890,
+ 46 Hydnum_rufescens_RU5_RUF4_UDB001465,
+ 47 Hydnum_rufescens_RU5_RUF5_UDB002423,
+ 48 Hydnum_rufescens_RU5_RUFHYD14_AJ547872,
+ 49 Hydnum_rufescens_RU6_RUF1_AY817137,
+ 50 Hydnum_rufescens_RU6_RUFHYD15_AJ547867,
+ 51 Hydnum_rufescens_wrong_taxonomy_RUF3_AM087246,
+ 52 Hydnum_umbilicatum_UMBHYD1_AJ534972,
+ 53 Hydnum_umbilicatum_UMBHYD2_AJ534973,
+ 54 Hydnum_vesterholtii_10429BIOFungi,
+ 55 Hydnum_vesterholtii_10452BIOFungi,
+ 56 Hydnum_vesterholtii_12330BIOFungi,
+ 57 Hydnum_vesterholtii_12904BIOFungi,
+ 58 Hydnum_vesterholtii_REPHYD12A_AJ547879,
+ 59 Hydnum_vesterholtii_REPHYD12C_AJ783968,
+ 60 Hydnum_vesterholtii_REPHYD13_AJ547887,
+ 61 Sistotrema_muscicola_AJ606040,
+ 62 Sistotrema_alboluteum_AJ606042;
+ TREE Fig._2 =3D [&R] ((62:100.0,(51:100.0,61:100.0):93.269997):49.66=
,((4:100.0,(2:100.0,3:100.0):100.0):60.639999,(((56:100.0,58:100.0,59:100.0=
):84.639999,(54:100.0,55:100.0,57:100.0,60:100.0):98.330002):92.5,(((30:100=
.0,31:100.0,32:100.0):100.0,(11:100.0,12:100.0,13:100.0,14:100.0,15:100.0,1=
6:100.0,17:100.0,18:100.0,19:100.0,20:100.0,21:100.0,22:100.0,23:100.0,24:1=
00.0,25:100.0,26:100.0):99.93):68.690002,(((33:100.0,34:100.0):49.8050005,(=
35:100.0,36:100.0,37:100.0,38:100.0):99.989998):49.8050005,((7:100.0,8:100.=
0,9:100.0,10:100.0):100.0,(42:100.0,(39:100.0,40:100.0,41:100.0):98.449997)=
:86.790001,((52:100.0,53:100.0):99.93,(1:100.0,(5:97.47999949999999,6:100.0=
):97.47999949999999):100.0):53.310001,(27:100.0,(28:100.0,29:100.0,49:100.0=
,50:100.0):47.404999):47.404999,(43:100.0,44:100.0,45:100.0,46:100.0,47:100=
.0,48:100.0):99.459999):29.245001):29.245001):51.580002):61.540001):49.66);
+ TREE PAUP_1 =3D [&R] ((62:100.0,(51:100.0,61:100.0):93.269997):49.66=
,((4:100.0,(3:100.0,2:100.0):100.0):60.639999,(((58:100.0,59:100.0,56:100.0=
):84.639999,(60:100.0,54:100.0,55:100.0,57:100.0):98.330002):92.5,(((30:100=
.0,31:100.0,32:100.0):100.0,(19:100.0,20:100.0,21:100.0,22:100.0,23:100.0,2=
4:100.0,25:100.0,26:100.0,17:100.0,18:100.0,11:100.0,12:100.0,13:100.0,14:1=
00.0,15:100.0,16:100.0):99.93):68.690002,((34:100.0,33:100.0):99.610001,(37=
:100.0,38:100.0,35:100.0,36:100.0):99.989998,(42:100.0,(39:100.0,41:100.0,4=
0:100.0):98.449997):86.790001,(8:100.0,7:100.0,9:100.0,10:100.0):100.0,((52=
:100.0,53:100.0):99.93,(1:100.0,(5:100.0,6:100.0):94.959999):100.0):53.3100=
01,(29:100.0,27:100.0,28:100.0,50:100.0,49:100.0):94.809998,(44:100.0,43:10=
0.0,48:100.0,45:100.0,46:100.0,47:100.0):99.459999):58.490002):51.580002):6=
1.540001):49.66);
+
+
+
+END;
diff -r b1f2c51d6bd8d8b1aecce8f62304cc2df278ccec -r f6d9557b6d77bde1c8049ba=
ffb65374729d51b89 test-data/visualization/phyloviz/2_nexus.nex
--- /dev/null
+++ b/test-data/visualization/phyloviz/2_nexus.nex
@@ -0,0 +1,96 @@
+#NEXUS
+
+[!This data set was downloaded from TreeBASE, a relational database of phy=
logenetic knowledge. TreeBASE has been supported by the NSF, Harvard Univer=
sity, Yale University, SDSC and UC Davis. Please do not remove this acknowl=
edgment from the Nexus file.
+
+
+Generated on August 18, 2012; 12:14 GMT
+
+TreeBASE (cc) 1994-2008
+
+Study reference:
+Naish D., Dyke G., Cau A., & Escuilli=C3=A9 F. 2012. A gigantic bird from =
the Upper Cretaceous
+of Central Asia. Biology Letters, 8(1): 97-100.
+
+TreeBASE Study URI: http://purl.org/phylo/treebase/phylows/study/TB2:S130=
08]
+
+BEGIN TREES;
+ TITLE Imported_trees;
+ LINK TAXA =3D Taxa1;
+ TRANSLATE
+ 1 Herrerasaurus,
+ 2 Tawa,
+ 3 Allosaurus,
+ 4 Alvarezsaurus,
+ 5 Anchiornis,
+ 6 Archaeopteryx,
+ 7 Archaeorhynchus,
+ 8 Avimimus,
+ 9 Baryonyx,
+ 10 Beipiaosaurus,
+ 11 Caenagnathus,
+ 12 Caudipteryx,
+ 13 Ceratosaurus,
+ 14 Chirostenotes,
+ 15 Citipati,
+ 16 Compsognathus,
+ 17 Confuciusornis,
+ 18 Dilong,
+ 19 Dilophosaurus,
+ 20 Epidendrosaurus,
+ 21 Epidexipteryx,
+ 22 Erlicosaurus,
+ 23 Eustreptospondylus,
+ 24 Gallimimus,
+ 25 Garudimimus,
+ 26 Gobipteryx,
+ 27 Guanlong,
+ 28 Haplocheirus,
+ 29 Harpymimus,
+ 30 Hebeiornis,
+ 31 Hongshanornis,
+ 32 Huoshanornis,
+ 33 Iberomesornis,
+ 34 Ichthyornis,
+ 35 Incisivosaurus,
+ 36 Jeholornis,
+ 37 Limusaurus,
+ 38 Longicrusavis,
+ 39 Longipteryx,
+ 40 Longirostravis,
+ 41 Majungasaurus,
+ 42 Masiakasaurus,
+ 43 Monolophosaurus,
+ 44 Mononykus,
+ 45 Neornithes,
+ 46 Ornitholestes,
+ 47 Ornithomimus,
+ 48 Patagonykus,
+ 49 Patagopteryx,
+ 50 Pelecanimimus,
+ 51 Pengornis,
+ 52 Protarchaeopteryx,
+ 53 Protopteryx,
+ 54 Rinchenia,
+ 55 Sapeornis,
+ 56 Segnosaurus,
+ 57 Shenzhousaurus,
+ 58 Shuvuuia,
+ 59 Sinornithosaurus,
+ 60 Sinosauropteryx,
+ 61 Sinovenator,
+ 62 Sinraptor,
+ 63 Syntarsus_kayentakatae,
+ 64 Troodon,
+ 65 Tyrannosaurus,
+ 66 Velociraptor,
+ 67 Yanornis,
+ 68 Yixianornis,
+ 69 Zhongjianornis,
+ 70 Zhongornis,
+ 71 Zuolong,
+ 72 Samrukia;
+ TREE Figure_1A =3D [&R] (1,(2,(((((43,(3,62)),(71,((46,((((28,(4,(48=
,(44,58)))),((((5,(61,(64,(59,66)))),(6,((36,(55,(69,(((7,34,45,49,72,(31,3=
8),(67,68)),(33,((32,((26,30),(39,40))),(51,53)))),(17,70))))),(20,21)))),(=
(11,(12,(8,(14,(15,54))))),(35,52))),(10,(22,56)))),(50,(57,(29,(25,(24,47)=
))))),(16,60))),(27,(18,65))))),(9,23)),(13,(41,(37,42)))),(19,63))));
+
+
+
+END;
diff -r b1f2c51d6bd8d8b1aecce8f62304cc2df278ccec -r f6d9557b6d77bde1c8049ba=
ffb65374729d51b89 test-data/visualization/phyloviz/3_phyloxml.xml
--- /dev/null
+++ b/test-data/visualization/phyloviz/3_phyloxml.xml
@@ -0,0 +1,257 @@
+<?xml version=3D"1.0" encoding=3D"UTF-8"?>
+<phyloxml xmlns:xsi=3D"http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation=3D"http://www.phyloxml.org http://www.phyloxml.org/1=
.10/phyloxml.xsd"
+ xmlns=3D"http://www.phyloxml.org">
+ <phylogeny rooted=3D"true">
+ <clade>
+ <clade>
+ <branch_length>0.18105</branch_length>
+ <confidence type=3D"unknown">89.0</confidence>
+ <clade>
+ <branch_length>0.07466</branch_length>
+ <confidence type=3D"unknown">32.0</confidence>
+ <clade>
+ <branch_length>0.26168</branch_length>
+ <confidence type=3D"unknown">100.0</confidence>
+ <clade>
+ <branch_length>0.22058</branch_length>
+ <confidence type=3D"unknown">89.0</confidence>
+ <clade>
+ <branch_length>0.28901</branch_length>
+ <confidence type=3D"unknown">100.0</confidence>
+ <clade>
+ <branch_length>0.06584</branch_length>
+ <confidence type=3D"unknown">100.0</confidence>
+ <clade>
+ <branch_length>0.02309</branch_length>
+ <confidence type=3D"unknown">43.0</confidenc=
e>
+ <clade>
+ <branch_length>0.0746</branch_length>
+ <confidence type=3D"unknown">100.0</confi=
dence>
+ <clade>
+ <branch_length>0.02365</branch_length>
+ <confidence type=3D"unknown">88.0</con=
fidence>
+ <clade>
+ <name>22_MOUSE</name>
+ <branch_length>0.05998</branch_leng=
th>
+ <taxonomy>
+ <code>MOUSE</code>
+ </taxonomy>
+ </clade>
+ <clade>
+ <name>Apaf-1_HUMAN</name>
+ <branch_length>0.01825</branch_leng=
th>
+ <taxonomy>
+ <code>HUMAN</code>
+ </taxonomy>
+ </clade>
+ </clade>
+ <clade>
+ <name>12_CANFA</name>
+ <branch_length>0.04683</branch_length>
+ <taxonomy>
+ <code>CANFA</code>
+ </taxonomy>
+ </clade>
+ </clade>
+ <clade>
+ <name>11_CHICK</name>
+ <branch_length>0.15226</branch_length>
+ <taxonomy>
+ <code>CHICK</code>
+ </taxonomy>
+ </clade>
+ </clade>
+ <clade>
+ <name>16_XENLA</name>
+ <branch_length>0.4409</branch_length>
+ <taxonomy>
+ <code>XENLA</code>
+ </taxonomy>
+ </clade>
+ </clade>
+ <clade>
+ <branch_length>0.17031</branch_length>
+ <confidence type=3D"unknown">100.0</confidence>
+ <clade>
+ <branch_length>0.10929</branch_length>
+ <confidence type=3D"unknown">100.0</confiden=
ce>
+ <clade>
+ <name>14_FUGRU</name>
+ <branch_length>0.02255</branch_length>
+ <taxonomy>
+ <code>FUGRU</code>
+ </taxonomy>
+ </clade>
+ <clade>
+ <name>15_TETNG</name>
+ <branch_length>0.09478</branch_length>
+ <taxonomy>
+ <code>TETNG</code>
+ </taxonomy>
+ </clade>
+ </clade>
+ <clade>
+ <name>17_BRARE</name>
+ <branch_length>0.1811</branch_length>
+ <taxonomy>
+ <code>BRARE</code>
+ </taxonomy>
+ </clade>
+ </clade>
+ </clade>
+ <clade>
+ <branch_length>0.01594</branch_length>
+ <confidence type=3D"unknown">53.0</confidence>
+ <clade>
+ <branch_length>0.10709</branch_length>
+ <confidence type=3D"unknown">68.0</confidence>
+ <clade>
+ <name>1_BRAFL</name>
+ <branch_length>0.26131</branch_length>
+ <taxonomy>
+ <code>BRAFL</code>
+ </taxonomy>
+ </clade>
+ <clade>
+ <name>18_NEMVE</name>
+ <branch_length>0.38014</branch_length>
+ <taxonomy>
+ <code>NEMVE</code>
+ </taxonomy>
+ </clade>
+ </clade>
+ <clade>
+ <name>23_STRPU</name>
+ <branch_length>0.48179</branch_length>
+ <taxonomy>
+ <code>STRPU</code>
+ </taxonomy>
+ </clade>
+ </clade>
+ </clade>
+ <clade>
+ <branch_length>0.34475</branch_length>
+ <confidence type=3D"unknown">100.0</confidence>
+ <clade>
+ <name>26_STRPU</name>
+ <branch_length>0.36374</branch_length>
+ <taxonomy>
+ <code>STRPU</code>
+ </taxonomy>
+ <sequence>
+ <domain_architecture length=3D"1319">
+ <domain from=3D"18" to=3D"98" confidence=3D"=
3.4E-5">Death</domain>
+ <domain from=3D"189" to=3D"481" confidence=
=3D"1.8E-10">NB-ARC</domain>
+ <domain from=3D"630" to=3D"668" confidence=
=3D"8.2E-5">WD40</domain>
+ </domain_architecture>
+ </sequence>
+ </clade>
+ <clade>
+ <name>25_STRPU</name>
+ <branch_length>0.33137</branch_length>
+ <taxonomy>
+ <code>STRPU</code>
+ </taxonomy>
+ <sequence>
+ <domain_architecture length=3D"1947">
+ <domain from=3D"143" to=3D"227" confidence=
=3D"7.4E-5">Death</domain>
+ <domain from=3D"227" to=3D"550" confidence=
=3D"2.0E-13">NB-ARC</domain>
+ <domain from=3D"697" to=3D"736" confidence=
=3D"7.9E-4">WD40</domain>
+ <domain from=3D"745" to=3D"785" confidence=
=3D"1.5">WD40</domain>
+ <domain from=3D"1741" to=3D"1836" confidence=
=3D"2.0">Adeno_VII</domain>
+ </domain_architecture>
+ </sequence>
+ </clade>
+ </clade>
+ </clade>
+ <clade>
+ <branch_length>1.31498</branch_length>
+ <confidence type=3D"unknown">100.0</confidence>
+ <clade>
+ <name>CED4_CAEEL</name>
+ <branch_length>0.13241</branch_length>
+ <taxonomy>
+ <code>CAEEL</code>
+ </taxonomy>
+ <sequence>
+ <domain_architecture length=3D"714">
+ <domain from=3D"7" to=3D"90" confidence=3D"9.2E=
-14">CARD</domain>
+ <domain from=3D"116" to=3D"442" confidence=3D"5=
.8E-151">NB-ARC</domain>
+ </domain_architecture>
+ </sequence>
+ </clade>
+ <clade>
+ <name>31_CAEBR</name>
+ <branch_length>0.04777</branch_length>
+ <taxonomy>
+ <code>CAEBR</code>
+ </taxonomy>
+ <sequence>
+ <domain_architecture length=3D"554">
+ <domain from=3D"1" to=3D"75" confidence=3D"0.00=
46">CARD</domain>
+ <domain from=3D"101" to=3D"427" confidence=3D"2=
.1E-123">NB-ARC</domain>
+ </domain_architecture>
+ </sequence>
+ </clade>
+ </clade>
+ </clade>
+ <clade>
+ <branch_length>0.13172</branch_length>
+ <confidence type=3D"unknown">45.0</confidence>
+ <clade>
+ <branch_length>0.24915</branch_length>
+ <confidence type=3D"unknown">95.0</confidence>
+ <clade>
+ <branch_length>0.76898</branch_length>
+ <confidence type=3D"unknown">100.0</confidence>
+ <clade>
+ <name>28_DROPS</name>
+ <branch_length>0.1732</branch_length>
+ <taxonomy>
+ <code>DROPS</code>
+ </taxonomy>
+ <sequence>
+ <domain_architecture length=3D"535">
+ <domain from=3D"112" to=3D"399" confidence=
=3D"1.4E-5">NB-ARC</domain>
+ </domain_architecture>
+ </sequence>
+ </clade>
+ <clade>
+ <name>Dark_DROME</name>
+ <branch_length>0.18863</branch_length>
+ <taxonomy>
+ <code>DROME</code>
+ </taxonomy>
+ <sequence>
+ <domain_architecture length=3D"1421">
+ <domain from=3D"108" to=3D"397" confidence=
=3D"2.1E-5">NB-ARC</domain>
+ </domain_architecture>
+ </sequence>
+ </clade>
+ </clade>
+ <clade>
+ <name>29_AEDAE</name>
+ <branch_length>0.86398</branch_length>
+ <taxonomy>
+ <code>AEDAE</code>
+ </taxonomy>
+ <sequence>
+ <domain_architecture length=3D"423">
+ <domain from=3D"109" to=3D"421" confidence=3D"9=
.3E-6">NB-ARC</domain>
+ </domain_architecture>
+ </sequence>
+ </clade>
+ </clade>
+ <clade>
+ <name>30_TRICA</name>
+ <branch_length>0.97698</branch_length>
+ <taxonomy>
+ <code>TRICA</code>
+ </taxonomy>
+ </clade>
+ </clade>
+ </clade>
+ </clade>
+ </phylogeny>
+</phyloxml>
diff -r b1f2c51d6bd8d8b1aecce8f62304cc2df278ccec -r f6d9557b6d77bde1c8049ba=
ffb65374729d51b89 test-data/visualization/phyloviz/4_newick.nhx
--- /dev/null
+++ b/test-data/visualization/phyloviz/4_newick.nhx
@@ -0,0 +1,33 @@
+(((BGIOSIBCA028421_ORYSA:0.423485[&&NHX:S=3DORYSA:O=3DBGIOSIBCA028421.1:G=
=3DBGIOSIBCA028421],
+At5g41150_ARATH:0.273135[&&NHX:S=3DARATH:O=3DAt5g41150.1:G=3DAt5g41150]
+):0.690991[&&NHX:S=3DMagnoliophyta:D=3DN:B=3D100],
+(rad16_SCHPO:0.718598[&&NHX:S=3DSCHPO:O=3DSPCC970.01:G=3DSPCC970.01],
+RAD1_YEAST:1.05456[&&NHX:S=3DYEAST:O=3DYPL022W.1:G=3DYPL022W]
+):0.344838[&&NHX:S=3DAscomycota:D=3DN:B=3D100]
+):0.103849[&&NHX:S=3DEukaryota:D=3DN:B=3D61],
+((((((((ERCC4_HUMAN:0.067531[&&NHX:S=3DHUMAN:O=3DENST00000311895.3:G=3DENS=
G00000175595],
+Ercc4_MOUSE:0.17422[&&NHX:S=3DMOUSE:O=3DENSMUST00000023206.5:G=3DENSMUSG00=
000022545]
+):0.065513[&&NHX:S=3DEuarchontoglires:D=3DN:B=3D100],
+ENSMODT00000006086_MONDO:0.104633[&&NHX:S=3DMONDO:O=3DENSMODT00000006086.2=
:G=3DENSMODG00000004840]
+):0.083764[&&NHX:S=3DTheria:D=3DN:B=3D100],
+Q5ZJP8_CHICK:0.153132[&&NHX:S=3DCHICK:O=3DENSGALT00000004716.2:G=3DENSGALG=
00000002981]
+):0.057998[&&NHX:S=3DAmniota:D=3DN:B=3D100],
+ENSXETT00000024054_XENTR:0.288632[&&NHX:S=3DXENTR:O=3DENSXETT00000024054.2=
:G=3DENSXETG00000010991]
+):0.075713[&&NHX:S=3DTetrapoda:D=3DN:B=3D100],
+(zgc-63468_BRARE:0.2218[&&NHX:S=3DBRARE:O=3DENSDART00000015780.4:G=3DENSDA=
RG00000014161],
+NEWSINFRUT00000137921_FUGRU:0.220441[&&NHX:S=3DFUGRU:O=3DNEWSINFRUT0000013=
7921.3:G=3DNEWSINFRUG00000130312]
+):0.170605[&&NHX:S=3DClupeocephala:D=3DN:B=3D100]
+):0.238713[&&NHX:S=3DEuteleostomi:D=3DN:B=3D100],
+ENSCINT00000011737_CIOIN:0.623567[&&NHX:S=3DCIOIN:O=3DENSCINT00000011737.2=
:G=3DENSCING00000005673]
+):0.07499[&&NHX:S=3DChordata:D=3DN:B=3D100],
+(Sm00.scaff00195.0600_SCHMA:0.784609[&&NHX:S=3DSCHMA:O=3DSm00.scaff00195.0=
600:G=3DSm00.scaff00195.0600],
+(CBG03141_CAEBR:0.093703[&&NHX:S=3DCAEBR:O=3DCBG03141:G=3DCBG03141],
+NP_496498_CAEEL:0.212236[&&NHX:S=3DCAEEL:O=3DC47D12.8.1:G=3DC47D12.8]
+):1.47416[&&NHX:S=3DCaenorhabditis:D=3DN:B=3D94]
+):0.26906[&&NHX:S=3DBilateria:D=3DN:B=3D97]
+):0.071406[&&NHX:S=3DBilateria:D=3DN:B=3D1],
+(mei-9-RA_DROME:0.170289[&&NHX:S=3DDROME:O=3DCG3697-RA.3:G=3DCG3697],
+GA17620-PA_DROPS:0.154817[&&NHX:S=3DDROPS:O=3DGA17620-PA:G=3DGA17620]
+):0.818474[&&NHX:S=3DSophophora:D=3DN:B=3D100]
+):0
+)[&&NHX:S=3DEukaryota:D=3DN];
\ No newline at end of file
diff -r b1f2c51d6bd8d8b1aecce8f62304cc2df278ccec -r f6d9557b6d77bde1c8049ba=
ffb65374729d51b89 test-data/visualization/phyloviz/5_newick.nhx
--- /dev/null
+++ b/test-data/visualization/phyloviz/5_newick.nhx
@@ -0,0 +1,1 @@
+(CAE_ELE_PORCN:0.303421 ,((((DRO_PER_PORCN:0.001000 ,DRO_PSE_PORCN:0.00100=
0 )67:0.141994 ,(DRO_ANA_PORCN:0.111899 ,(DRO_ERE_PORCN:0.030516 ,(DRO_MEL_=
PORCN:0.021127 ,DRO_SEC_PORCN:0.021127 )38:0.030516 )35:0.111899 )18:0.1419=
94 )16:0.162611 ,(DRO_WIL_PORCN:0.152225 ,(DRO_VIR_PORCN:0.085057 ,DRO_MOJ_=
PORCN:0.085057 )24:0.152225 )15:0.162611 )13:0.295081 ,(ANO_GAM_PORCN:0.287=
545 ,((CIO_INT_PORCN:0.100686 ,CIO_SAV_PORCN:0.100686 )19:0.275542 ,((LOA_L=
OA_PORCN:0.036278 ,BRU_MAL_PORCN:0.036278 )29:0.272631 ,(((((DAN_RER_PORCN:=
0.086499 ,((TAK_RUB_PORCN:0.032609 ,TET_NIG_PORCN:0.032609 )32:0.048864 ,(G=
AD_MOR_PORCN:0.039387 ,(ORY_LAT_PORCN:0.031729 ,(GAS_ACU_PORCN:0.021882 ,OR=
E_NIL_PORCN:0.021882 )37:0.031729 )34:0.039387 )28:0.048864 )27:0.086499 )2=
3:0.119618 ,(LAT_CHA_PORCN:0.099348 ,((XEN_LAE_PORCN:0.033333 ,XEN_TRO_PORC=
N:0.033333 )31:0.091250 ,(ANO_CAR_PORCN:0.086538 ,((MON_DOM_PORCN:0.014100 =
,(MAC_EUG_PORCN:0.005423 ,SAR_HAR_PORCN:0.005423 )57:0.014100 )42:0.062862 =
,(ORN_ANA_PORCN:0.057974 ,(GOR_GOR_PORCN:0.033876 ,(FEL_CAT_PORCN:0.022851 =
,(PRO_CAP_PORCN:0.019716 ,(CAV_POR_PORCN:0.018599 ,(ERI_EUR_PORCN:0.015518 =
,((DIP_ORD_PORCN:0.007231 ,(MUS_MUS_PORCN:0.001085 ,(RAT_NOR_PORCN:0.001000=
,CRI_GRI_PORCN:0.001000 )69:0.001085 )64:0.007231 )53:0.012954 ,(DAS_NOV_P=
ORCN:0.011362 ,(LOX_AFR_PORCN:0.010575 ,(CAL_JAC_PORCN:0.010332 ,(OCH_PRI_P=
ORCN:0.010063 ,(MIC_MUR_PORCN:0.009123 ,(SUS_SCR_PORCN:0.008880 ,(MYO_LUC_P=
ORCN:0.008460 ,((CAN_FAM_PORCN:0.005423 ,AIL_MEL_PORCN:0.005423 )58:0.00809=
3 ,((PTE_VAM_PORCN:0.006508 ,BOS_TAU_PORCN:0.006508 )55:0.007494 ,((SPE_TRI=
_PORCN:0.003254 ,TUP_BEL_PORCN:0.003254 )61:0.006929 ,((OTO_GAR_PORCN:0.001=
085 ,(ORY_CUN_PORCN:0.001000 ,TUR_TRU_PORCN:0.001000 )68:0.001085 )65:0.005=
965 ,(EQU_CAB_PORCN:0.003688 ,(MAC_MUL_PORCN:0.002711 ,(PAN_TRO_PORCN:0.001=
446 ,(HOM_SAP_PORCN:0.001085 ,(PON_ABE_PORCN:0.001000 ,NOM_LEU_PORCN:0.0010=
00 )70:0.001085 )66:0.001446 )63:0.002711 )62:0.003688 )60:0.005965 )56:0.0=
06929 )54:0.007494 )52:0.008093 )51:0.008460 )50:0.008880 )49:0.009123 )48:=
0.010063 )47:0.010332 )46:0.010575 )45:0.011362 )44:0.012954 )43:0.015518 )=
41:0.018599 )40:0.019716 )39:0.022851 )36:0.033876 )30:0.057974 )26:0.06286=
2 )25:0.086538 )22:0.091250 )21:0.099348 )20:0.119618 )17:0.214465 ,(BRA_FL=
O_PORCN:0.189220 ,SAC_KOW_PORCN:0.189220 )12:0.214465 )11:0.257058 ,(NEM_VE=
C_PORCN:0.246631 ,AMP_QUE_PORCN:0.246631 )9:0.257058 )8:0.266904 ,(TRI_CAS_=
PORCN:0.259494 ,(PED_HUM_PORCN:0.227009 ,(NAS_VIT_PORCN:0.160241 ,(API_MEL_=
PORCN:0.031851 ,(BOM_TER_PORCN:0.004808 ,BOM_IMP_PORCN:0.004808 )59:0.03185=
1 )33:0.160241 )14:0.227009 )10:0.259494 )7:0.266904 )6:0.272631 )5:0.27554=
2 )4:0.287545 )3:0.295081 )2:0.303421 )1:0.0001;
https://bitbucket.org/galaxy/galaxy-central/changeset/75a03bacdc7a/
changeset: 75a03bacdc7a
user: jgoecks
date: 2012-08-27 20:08:55
summary: Merged in Tomithy/galaxy-central-phyloviz-2 (pull request #65)
affected #: 19 files
diff -r 89dbce43ba88afdc3e6265feea7e7e042bb030a7 -r 75a03bacdc7a3dc5b1c03f8=
b02df0ab383366955 lib/galaxy/datatypes/data.py
--- a/lib/galaxy/datatypes/data.py
+++ b/lib/galaxy/datatypes/data.py
@@ -719,7 +719,49 @@
pass
=20
class Newick( Text ):
- pass
+ """New Hampshire/Newick Format"""
+ file_ext =3D "nhx"
+
+ MetadataElement( name=3D"columns", default=3D3, desc=3D"Number of colu=
mns", readonly=3DTrue )
+
+ def __init__(self, **kwd):
+ """Initialize foobar datatype"""
+ Text.__init__(self, **kwd)
+
+ def init_meta( self, dataset, copy_from=3DNone ):
+ Text.init_meta( self, dataset, copy_from=3Dcopy_from )
+
+
+ def sniff( self, filename ):
+ """ Returning false as the newick format is too general and cannot=
be sniffed."""
+ return False
+
+
+class Nexus( Text ):
+ """Nexus format as used By Paup, Mr Bayes, etc"""
+ file_ext =3D "nex"
+
+ MetadataElement( name=3D"columns", default=3D3, desc=3D"Number of colu=
mns", readonly=3DTrue )
+
+ def __init__(self, **kwd):
+ """Initialize foobar datatype"""
+ Text.__init__(self, **kwd)
+
+ def init_meta( self, dataset, copy_from=3DNone ):
+ Text.init_meta( self, dataset, copy_from=3Dcopy_from )
+
+
+ def sniff( self, filename ):
+ """All Nexus Files Simply puts a '#NEXUS' in its first line"""
+ f =3D open(filename, "r")
+ firstline =3D f.readline().upper()
+ f.close()
+
+ if "#NEXUS" in firstline:
+ return True
+ else:
+ return False
+
=20
# ------------- Utility methods --------------
=20
diff -r 89dbce43ba88afdc3e6265feea7e7e042bb030a7 -r 75a03bacdc7a3dc5b1c03f8=
b02df0ab383366955 lib/galaxy/datatypes/xml.py
--- a/lib/galaxy/datatypes/xml.py
+++ b/lib/galaxy/datatypes/xml.py
@@ -76,3 +76,24 @@
dataset.blurb =3D 'file purged from disk'
def sniff( self, filename ):
return False
+
+class Phyloxml( GenericXml ):
+ """Format for defining phyloxml data http://www.phyloxml.org/"""
+ file_ext =3D "phyloxml"
+ def set_peek( self, dataset, is_multi_byte=3DFalse ):
+ """Set the peek and blurb text"""
+ if not dataset.dataset.purged:
+ dataset.peek =3D data.get_file_peek( dataset.file_name, is_mul=
ti_byte=3Dis_multi_byte )
+ dataset.blurb =3D 'Phyloxml data'
+ else:
+ dataset.peek =3D 'file does not exist'
+ dataset.blurb =3D 'file purged from disk'
+
+ def sniff( self, filename ):
+ """"Checking for keyword - 'phyloxml' always in lowercase in the f=
irst few lines"""
+ f =3D open(filename, "r")
+ firstlines =3D "".join(f.readlines(5))
+ f.close()
+ if "phyloxml" in firstlines:
+ return True
+ return False
\ No newline at end of file
diff -r 89dbce43ba88afdc3e6265feea7e7e042bb030a7 -r 75a03bacdc7a3dc5b1c03f8=
b02df0ab383366955 lib/galaxy/visualization/phyloviz/__init__.py
--- /dev/null
+++ b/lib/galaxy/visualization/phyloviz/__init__.py
@@ -0,0 +1,1 @@
+__author__ =3D 'Tomithy'
diff -r 89dbce43ba88afdc3e6265feea7e7e042bb030a7 -r 75a03bacdc7a3dc5b1c03f8=
b02df0ab383366955 lib/galaxy/visualization/phyloviz/baseparser.py
--- /dev/null
+++ b/lib/galaxy/visualization/phyloviz/baseparser.py
@@ -0,0 +1,125 @@
+import json
+
+class Node(object):
+ """Node class of PhyloTree, which represents a CLAUDE in a phylogeneti=
c tree"""
+ def __init__(self, nodeName, **kwargs):
+ """Creates a node and adds in the typical annotations"""
+ self.name, self.id =3D nodeName, kwargs.get("id", 0)
+ self.depth =3D kwargs.get("depth", 0)
+ self.children =3D []
+
+ self.isInternal =3D kwargs.get("isInternal", 0)
+ self.length, self.bootstrap =3D kwargs.get("length", 0), kwargs.ge=
t("bootstrap", None)
+ self.events =3D kwargs.get("events", "")
+
+ # clean up boot strap values
+ if self.bootstrap =3D=3D -1:
+ self.bootstrap =3D None
+
+ def addChildNode(self, child):
+ """Adds a child node to the current node"""
+ if isinstance(child, Node):
+ self.children.append(child)
+ else:
+ self.children +=3D 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 =3D {
+ "name" : self.name,
+ "id" : self.id,
+ "depth" : self.depth,
+ "dist" : self.length
+ }
+ thisJson =3D self.addChildrenToJson(thisJson)
+ thisJson =3D self.addMiscToJson(thisJson)
+ return thisJson
+
+ def addChildrenToJson(self, jsonDict):
+ """Needs a special method to addChildren, such that the key does n=
ot 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 =3D [ node.toJson() for node in self.children]
+ jsonDict["children"] =3D children
+ return jsonDict
+
+
+ def addMiscToJson(self, jsonDict):
+ """Adds other misc attributes to json if they are present"""
+ if not self.events =3D=3D "":
+ jsonDict["events"] =3D self.events
+ if not self.bootstrap =3D=3D None:
+ jsonDict["bootstrap"] =3D 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 =3D None, {}
+ self.nodes =3D {}
+ self.title =3D None
+ self.id =3D 1
+
+ def addAttributesToRoot(self, attrDict):
+ """Adds attributes to root, but first we put it in a temp store an=
d bind it with root when .toJson is called"""
+ for key, value in attrDict.items():
+ self.rootAttr[key] =3D 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"] =3D self.id
+ self.id +=3D 1
+ return Node(nodeName, **kwargs)
+
+ def addRoot(self, root):
+ """Creates a root for phyloTree"""
+ assert isinstance(root, Node)
+ root.parent =3D None
+ self.root =3D root
+
+ def generateJsonableDict(self):
+ """Changes itself into a dictonary by recurssively calling the toj=
son on all its nodes. Think of it
+ as a dict in an array of dict in an array of dict and so on..."""
+ jsonTree =3D ""
+ if self.root:
+ assert isinstance(self.root, Node)
+ jsonTree =3D self.root.toJson()
+ for key, value in self.rootAttr.items():
+ # transfer temporary stored attr to root
+ jsonTree[key] =3D value
+ else:
+ raise Exception("Root is not assigned!")
+ return jsonTree
+
+
+
+class Base_Parser(object):
+ """Base parsers contain all the methods to handle phylogeny tree creat=
ion and
+ converting the data to json that all parsers should have"""
+
+ def __init__(self):
+ self.phyloTrees =3D []
+
+ def parseFile(self, filePath):
+ """Base method that all phylogeny file parser should have"""
+ raise Exception("Base method for phylogeny file parsers is not imp=
lemented")
+
+ 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 =3D open(filepath, "w")
+ f.writelines(json)
+ f.close()
diff -r 89dbce43ba88afdc3e6265feea7e7e042bb030a7 -r 75a03bacdc7a3dc5b1c03f8=
b02df0ab383366955 lib/galaxy/visualization/phyloviz/newickparser.py
--- /dev/null
+++ b/lib/galaxy/visualization/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 b=
y 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: json=
ableDict"""
+ with open(filePath, "r") as newickFile:
+ newickString =3D newickFile.read()
+ newickString =3D 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: j=
sonableDict"""
+ return self._parseNewickToJson(newickString)
+
+
+ def _parseNewickToJson(self, newickString, treeName=3DNone, nameMap=3D=
None):
+ """parses a newick representation of a tree into a PhyloTree data =
structure,
+ which can be easily converted to json"""
+ self.phyloTree =3D PhyloTree()
+ newickString =3D self.cleanNewickString(newickString)
+ if nameMap:
+ newickString =3D self._mapName(newickString, nameMap)
+
+ self.phyloTree.root =3D 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 wh=
ite spaces"""
+ return re.sub(r'\s|;|\"|\'|\\', '', rawNewick)
+
+
+ def _makeNodesFromString(self, string, depth):
+ """elements separated by comma could be empty"""
+
+ if string.find("(") !=3D -1:
+ raise Exception("Tree is not well form, location: " + string)
+
+ childrenString =3D string.split(",")
+ childrenNodes =3D []
+
+ for childString in childrenString:
+ if len(childString) =3D=3D 0:
+ continue
+ nodeInfo =3D childString.split(":")
+ name, length, bootstrap =3D "", None, -1
+ if len(nodeInfo) =3D=3D 2: # has length info
+ length =3D nodeInfo[1]
+ # checking for bootstap values
+ name =3D nodeInfo[0]
+ try: # Nexus may bootstrap in names position
+ name =3D float(name)
+ if 0<=3D name <=3D 1:
+ bootstrap =3D name
+ elif 1 <=3D name <=3D 100:
+ bootstrap =3D name / 100
+ name =3D ""
+ except ValueError:
+ name =3D nodeInfo[0]
+ else:
+ name =3D nodeInfo[0] # string only contains name
+ node =3D self.phyloTree.makeNode(name, length=3Dlength, depth=
=3Ddepth, bootstrap=3D bootstrap)
+ childrenNodes +=3D [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 outsi=
de of quotes(" ")
+ """
+ newString =3D ""
+ start =3D 0
+ end =3D 0
+
+ for i in xrange(len(newickString)):
+ if newickString[i] =3D=3D "(" or newickString[i] =3D=3D ",":
+ if re.match(r"[,(]", newickString[i+1:]):
+ continue
+ else:
+ end =3D 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 t=
erm
+ for j in xrange(i+1, len(newickString)):
+ enclosingSymbol =3D newickString[j] # the immedi=
ate symbol after a common or left bracket which denotes the end of a term
+ if enclosingSymbol =3D=3D ")" or enclosingSymbol =
=3D=3D ":" or enclosingSymbol =3D=3D ",":
+ termToReplace =3D newickString[end:j]
+
+ newString +=3D newickString[start : end] + na=
meMap[termToReplace] #+ "'" "'" +
+ start =3D j
+ break
+
+ newString +=3D 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 no=
de C, its children D, E,
+ and finally the succeeding nodes F, G"""
+
+ # Base case where there is only an empty string
+ if string =3D=3D "":
+ return
+ # Base case there its only an internal claude
+ if string.find("(") =3D=3D -1:
+ return self._makeNodesFromString(string, depth)
+
+ nodes, children =3D [], [] # nodes refer to the nodes on this=
level, children refers to the child of the
+ start =3D 0
+ lenOfPreceedingInternalNodeString =3D 0
+ bracketStack =3D []
+
+ for j in xrange(len(string)):
+ if string[j] =3D=3D "(": #finding the positions of all the =
open brackets
+ bracketStack.append(j)
+ continue
+ if string[j] =3D=3D ")": #finding the positions of all the =
closed brackets to extract claude
+ i =3D bracketStack.pop()
+
+ if len(bracketStack) =3D=3D 0: # is child of current node
+
+ InternalNode =3D None
+
+ #First flat call to make nodes of the same depth but f=
rom the preceeding string.
+ startSubstring =3D string[start + lenOfPreceedingInter=
nalNodeString: i]
+ preceedingNodes =3D self._makeNodesFromString(startSu=
bstring, depth)
+ nodes +=3D preceedingNodes
+
+ # Then We will try to see if the substring has any int=
ernal nodes first, make it then make nodes preceeding it and succeeding it.
+ if j + 1 < len(string):
+ stringRightOfBracket =3D string[j+1:] # Eg. '=
(b:0.4,a:0.3)c:0.3, stringRightOfBracket =3D c:0.3
+ match =3D re.search(r"[\)\,\(]", stringRightOfBrac=
ket)
+ if match:
+ indexOfNextSymbol =3D match.start()
+ stringRepOfInternalNode =3D stringRightOfBrack=
et[:indexOfNextSymbol]
+ internalNodes =3D self._makeNodesFromString( s=
tringRepOfInternalNode, depth)
+ if len(internalNodes) > 0:
+ InternalNode =3D internalNodes[0]
+ lenOfPreceedingInternalNodeString =3D len(stri=
ngRepOfInternalNode)
+ else: # sometimes the node can be the last eleme=
nt of a string
+ InternalNode =3D self._makeNodesFromString(str=
ing[j+1:], depth)[0]
+ lenOfPreceedingInternalNodeString =3D len(stri=
ng) - j
+ if InternalNode =3D=3D None: #creating a generic=
node if it is unnamed
+ InternalNode =3D self.phyloTree.makeNode( "", dept=
h=3Ddepth, isInternal=3DTrue ) #"internal-" + str(depth)
+ lenOfPreceedingInternalNodeString =3D 0
+
+ # recussive call to make the internal claude
+ childSubString =3D string[ i + 1 : j ]
+ InternalNode.addChildNode(self.parseNode(childSubStrin=
g, depth + 1))
+
+ nodes.append(InternalNode) # we append the internal n=
ode later to preserve order
+
+ start =3D j + 1
+ continue
+
+ if depth =3D=3D 0: # if its the root node, we do nothing about =
it and return
+ return nodes[0]
+
+ # Adding last most set of children
+ endString =3D string[start:]
+ if string[start-1] =3D=3D ")": # if the symbol belongs to an inte=
rnal node which is created previously, then we remove it from the string le=
ft to parse
+ match =3D re.search(r"[\)\,\(]", endString)
+ if match:
+ endOfNodeName =3D start + match.start() + 1
+ endString =3D string[endOfNodeName:]
+ nodes +=3D self._makeNodesFromString(endString, depth)
+
+ return nodes
diff -r 89dbce43ba88afdc3e6265feea7e7e042bb030a7 -r 75a03bacdc7a3dc5b1c03f8=
b02df0ab383366955 lib/galaxy/visualization/phyloviz/nexusparser.py
--- /dev/null
+++ b/lib/galaxy/visualization/phyloviz/nexusparser.py
@@ -0,0 +1,107 @@
+from newickparser import Newick_Parser
+import re
+
+MAX_READLINES =3D 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 be=
gin and another line starting with end;
+ Commends inside square brackets are to be ignored,
+ For more information: http://wiki.christophchamp.com/index.php/NEX=
US_file_format
+ Nexus can store multiple trees
+ """
+
+ with open( filename, "rt") as nex_file:
+ nexlines =3D nex_file.readlines()
+
+ rowCount =3D 0
+ inTreeBlock =3D False # sentinel to check if we are in a t=
ree block
+ intranslateBlock =3D False # sentinel to check if we are in the=
translate region of the tree. Stores synonyms of the labellings
+ self.inCommentBlock =3D False
+ self.nameMapping =3D None # stores mapping representation us=
ed in nexus format
+ treeNames =3D []
+
+ for line in nexlines:
+ line =3D line.replace(";\n", "")
+ lline =3D line.lower()
+
+ if rowCount > MAX_READLINES or (not nex_file) :
+ break
+ rowCount +=3D1
+ # We are only interested in the tree block.
+ if "begin" in lline and "tree" in lline and not inTreeBlock:
+ inTreeBlock =3D True
+ continue
+ if inTreeBlock and "end" in lline[:3]:
+ inTreeBlock, currPhyloTree =3D False, None
+ continue
+
+ if inTreeBlock:
+
+ if "title" in lline: # Adding title to the tree
+ titleLoc =3D lline.find("title")
+ title =3D line[titleLoc + 5:].replace(" ", "")
+
+ continue
+
+ if "translate" in lline:
+ intranslateBlock =3D True
+ self.nameMapping =3D {}
+ continue
+
+ if intranslateBlock:
+ mappingLine =3D self.splitLinebyWhitespaces(line)
+ key, value =3D mappingLine[1], mappingLine[2].replace(=
",", "").replace("'","") #replacing illegal json characters
+ self.nameMapping[key] =3D value
+
+ # Extracting newick Trees
+ if "tree" in lline:
+ intranslateBlock =3D False
+
+ treeLineCols =3D self.splitLinebyWhitespaces(line)
+ treeName, newick =3D treeLineCols[2], treeLineCols[-1]
+
+ if newick =3D=3D "": # Empty lines can be found in =
tree blocks
+ continue
+
+ currPhyloTree =3D self._parseNewickToJson(newick, tree=
Name, nameMap=3Dself.nameMapping)
+
+ self.phyloTrees.append(currPhyloTree)
+ treeIndex =3D len(self.phyloTrees) - 1
+ treeNames.append( (treeName, treeIndex) ) # appendi=
ng 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 ca=
n 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 =3D 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 an=
other is open.
+ else:
+ self.inCommentBlock =3D False
+ return "Nextline" # need to move on to the nextline =
after getting out of comment
+ return ""
\ No newline at end of file
diff -r 89dbce43ba88afdc3e6265feea7e7e042bb030a7 -r 75a03bacdc7a3dc5b1c03f8=
b02df0ab383366955 lib/galaxy/visualization/phyloviz/phyloviz_dataprovider.py
--- /dev/null
+++ b/lib/galaxy/visualization/phyloviz/phyloviz_dataprovider.py
@@ -0,0 +1,35 @@
+from newickparser import Newick_Parser
+from nexusparser import Nexus_Parser
+from phyloxmlparser import Phyloxml_Parser
+
+class Phyloviz_DataProvider(object):
+
+ def __init__(self):
+ pass
+
+ def parseFile(self, filepath, fileExt):
+ """returns [trees], meta
+ Trees are actually an array of JsonDicts. It's usually one tre=
e, except in the case of Nexus
+ """
+ jsonDicts, meta =3D [], {}
+ try:
+ if fileExt =3D=3D "nhx": # parses newick files
+ newickParser =3D Newick_Parser()
+ jsonDicts, parseMsg =3D newickParser.parseFile(filepath)
+ elif fileExt =3D=3D "phyloxml": # parses phyloXML files
+ phyloxmlParser =3D Phyloxml_Parser()
+ jsonDicts, parseMsg =3D phyloxmlParser.parseFile(filepath)
+ elif fileExt =3D=3D "nex": # parses nexus files
+ nexusParser =3D Nexus_Parser()
+ jsonDicts, parseMsg =3D nexusParser.parseFile(filepath)
+ meta["trees"] =3D parseMsg
+ else:
+ raise Exception("File type is not supported")
+
+ meta["msg"] =3D parseMsg
+
+ except Exception:
+ jsonDicts, meta["msg"] =3D [], "Parse failed"
+
+ return jsonDicts, meta
+
diff -r 89dbce43ba88afdc3e6265feea7e7e042bb030a7 -r 75a03bacdc7a3dc5b1c03f8=
b02df0ab383366955 lib/galaxy/visualization/phyloviz/phyloxmlparser.py
--- /dev/null
+++ b/lib/galaxy/visualization/phyloviz/phyloxmlparser.py
@@ -0,0 +1,145 @@
+from baseparser import Base_Parser, PhyloTree, Node
+from lxml import etree
+
+class Phyloxml_Parser(Base_Parser):
+ """Parses a phyloxml file into a json file that will be passed to Phyl=
oViz for display"""
+
+ def __init__(self):
+ super(Phyloxml_Parser, self).__init__()
+ self.phyloTree =3D PhyloTree()
+ self.tagsOfInterest =3D {
+ "clade": "",
+ "name" : "name",
+ "branch_length" : "length",
+ "confidence" : "bootstrap",
+ "events" : "events"
+ }
+
+ def parseFile(self, filePath):
+ """passes a file and extracts its Phylogeny Tree content."""
+ phyloXmlFile =3D open(filePath, "r")
+
+ xmlTree =3D etree.parse(phyloXmlFile)
+ xmlRoot =3D xmlTree.getroot()[0]
+ self.nameSpaceIndex =3D xmlRoot.tag.rfind("}") + 1 # used later by=
the clean tag method to remove the name space in every element.tag
+
+ phyloRoot =3D None
+ for child in xmlRoot:
+ childTag =3D self.cleanTag(child.tag)
+ if childTag =3D=3D "clade":
+ phyloRoot =3D child
+ elif childTag =3D=3D "name":
+ self.phyloTree.title =3D child.text
+
+ self.phyloTree.root =3D self.parseNode(phyloRoot, 0)
+ jsonDict =3D 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 =3D self.cleanTag(node.tag)
+ if not tag =3D=3D "clade":
+ return None
+ hasInnerClade =3D False
+
+ # peeking once for parent and once for child to check if the node =
is internal
+ for child in node:
+ childTag =3D self.cleanTag(child.tag)
+ if childTag =3D=3D "clade":
+ hasInnerClade =3D True
+ break
+
+ if hasInnerClade: # this node is an internal node
+ currentNode =3D self._makeInternalNode(node, depth=3D depth)
+ for child in node:
+ child =3D self.parseNode(child, depth + 1)
+ if isinstance(child, Node):
+ currentNode.addChildNode(child)
+
+ else: # this node is a leaf node
+ currentNode =3D self._makeLeafNode(node, depth=3Ddepth+1)
+
+ return currentNode
+
+
+ def _makeLeafNode(self, leafNode, depth =3D 0 ):
+ """Makes leaf nodes by calling Phylotree methods"""
+ node =3D {}
+ for child in leafNode:
+ childTag =3D self.cleanTag(child.tag)
+ if childTag in self.tagsOfInterest:
+ key =3D self.tagsOfInterest[childTag] # need to map phy=
loxml terms to ours
+ node[key] =3D child.text
+
+ node["depth"] =3D depth
+ return self.phyloTree.makeNode(self._getNodeName(leafNode), **node)
+
+ def _getNodeName(self, node, depth=3D-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 t=
o be treated differently as the name
+ is embedded one level deeper"""
+ phyloxmlTaxoNames =3D {
+ "common_name" : "",
+ "scientific_name" : "",
+ "code" : ""
+ }
+ for child in node:
+ childTag =3D self.cleanTag(child.tag)
+ if childTag in phyloxmlTaxoNames:
+ return child.text
+ return ""
+
+ nodeName =3D ""
+ for child in node:
+ childTag =3D self.cleanTag(child.tag)
+ if childTag =3D=3D "name" :
+ nodeName =3D child.text
+ break
+ elif childTag =3D=3D "taxonomy":
+ nodeName =3D getTagFromTaxonomyNode(child)
+ break
+
+ return nodeName
+
+
+ def _makeInternalNode(self, internalNode, depth=3D0):
+ """ Makes an internal node from an element object that is gurantee=
d 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 =3D {}
+ for child in internalNode:
+ childTag =3D self.cleanTag(child.tag)
+ if childTag =3D=3D "clade":
+ continue
+ elif childTag in self.tagsOfInterest:
+ if childTag =3D=3D "events": # events is nested 1 more =
level deeper than others
+ key, text =3D "events", self.cleanTag(child[0].tag)
+ else:
+ key =3D self.tagsOfInterest[childTag]
+ text =3D child.text
+ node[key] =3D text
+
+
+ return self.phyloTree.makeNode(self._getNodeName(internalNode, dep=
th), **node)
+
+
+ def cleanTag(self, tagString):
+ return tagString[self.nameSpaceIndex:]
+
+
+if __name__=3D=3D"__main__":
+
+ # Files tested against
+ parser =3D Phyloxml_Parser()
+ filepath =3D "../data/" +"apaf.xml"
+ # filepath =3D "../data/" +"12_multiple_supports.xml"
+
+ # filepath =3D "../data/" +"bcl_2.xml"
+ # filepath =3D "../data/" +"reducedXml.xml"
+ parser.parseFile(filepath)
diff -r 89dbce43ba88afdc3e6265feea7e7e042bb030a7 -r 75a03bacdc7a3dc5b1c03f8=
b02df0ab383366955 lib/galaxy/web/controllers/phyloviz.py
--- /dev/null
+++ b/lib/galaxy/web/controllers/phyloviz.py
@@ -0,0 +1,97 @@
+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_D=
ataProvider
+
+
+class PhyloVizController( BaseUIController, UsesVisualizationMixin, UsesHi=
storyDatasetAssociationMixin, 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 =3D None, **kwargs ):
+ """
+ The index method is called using phyloviz/ with a dataset id passe=
d in.
+ The relevant data set is then retrieved via get_json_from_datasetI=
d which interfaces with the parser
+ The json representation of the phylogenetic tree along with the co=
nfig is then written in the .mako template and passed back to the user
+ """
+ json, config =3D self.get_json_from_datasetId(trans, dataset_id)
+ config["saved_visualization"] =3D False
+ return trans.fill_template( "visualization/phyloviz.mako", data =
=3D json, config=3Dconfig)
+
+
+ @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 =3D self.get_visualization(trans, id)
+ config =3D self.get_visualization_config(trans, viz)
+ config["saved_visualization"] =3D True
+ data =3D config["root"]
+
+ return trans.fill_template( "visualization/phyloviz.mako", data =
=3D data, config=3Dconfig)
+
+
+ @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 =3D self.get_visualization(trans, viz_id)
+ viz_config =3D self.get_visualization_config(trans, viz)
+ viz_config["saved_visualization"] =3D True
+ return {
+ "data" : viz_config["root"],
+ "config" : viz_config
+ }
+
+
+ @web.expose
+ @web.json
+ def getJsonData(self, trans, dataset_id, treeIndex=3D0):
+ """
+ Method to retrieve data asynchronously via json format. Retriving =
from here rather than
+ making a direct datasets/ call allows for some processing and even=
t capturing
+ """
+ treeIndex =3D int(treeIndex)
+ json, config =3D self.get_json_from_datasetId(trans, dataset_id, t=
reeIndex)
+ packedJson =3D {
+ "data" : json,
+ "config" : config
+ }
+
+ return packedJson
+
+
+ def get_json_from_datasetId(self, trans, dataset_id, treeIndex=3D0):
+ """
+ For interfacing phyloviz controllers with phyloviz visualization d=
ata provider (parsers)
+ """
+ dataset =3D self.get_dataset(trans, dataset_id)
+ fileExt, filepath =3D dataset.ext, dataset.file_name # .name=
stores the name of the dataset from the orginal upload
+ json, config =3D "", {} # config contains propertie=
s of the tree and file
+
+ if fileExt =3D=3D "json":
+ something, json =3D self.get_data(dataset)
+ else:
+ try:
+ pd =3D Phyloviz_DataProvider()
+ json, config =3D pd.parseFile(filepath, fileExt)
+ json =3D json[treeIndex]
+ except Exception:
+ pass
+
+ config["title"] =3D dataset.display_name()
+ config["ext"] =3D fileExt
+ config["dataset_id"] =3D dataset_id
+ config["treeIndex"] =3D treeIndex
+
+ return json, config
diff -r 89dbce43ba88afdc3e6265feea7e7e042bb030a7 -r 75a03bacdc7a3dc5b1c03f8=
b02df0ab383366955 lib/galaxy/web/controllers/visualization.py
--- a/lib/galaxy/web/controllers/visualization.py
+++ b/lib/galaxy/web/controllers/visualization.py
@@ -16,6 +16,10 @@
action =3D "paramamonster"
elif item.type =3D=3D "circster":
action =3D "circster"
+ elif item.type =3D=3D "phyloviz":
+ # Support phyloviz
+ controller =3D "phyloviz"
+ action =3D "visualization"
return dict( controller=3Dcontroller, action=3Daction, id=3Ditem.i=
d )
=20
# Grid definition
diff -r 89dbce43ba88afdc3e6265feea7e7e042bb030a7 -r 75a03bacdc7a3dc5b1c03f8=
b02df0ab383366955 static/scripts/viz/phyloviz.js
--- /dev/null
+++ b/static/scripts/viz/phyloviz.js
@@ -0,0 +1,955 @@
+var UserMenuBase =3D Backbone.View.extend({
+ /**
+ * Base class of any menus that takes in user interaction. Contains ch=
ecking methods.
+ */
+
+ className: 'UserMenuBase',
+
+ isAcceptableValue : function ($inputKey, min, max) {
+ /**
+ * Check if an input value is a number and falls within max min.
+ */
+ var self =3D this,
+ value =3D $inputKey.val(),
+ fieldName =3D $inputKey.attr("displayLabel") || $inputKey.attr=
("id").replace("phyloViz", "");
+
+ function isNumeric(n) {
+ return !isNaN(parseFloat(n)) && isFinite(n);
+ }
+
+ if (!isNumeric(value)){
+ alert(fieldName + " is not a number!");
+ return false;
+ }
+
+ if ( value > max){
+ alert(fieldName + " is too large.");
+ return false;
+ } else if ( value < min) {
+ alert(fieldName + " is too small.");
+ return false;
+ }
+ return true;
+ },
+
+ hasIllegalJsonCharacters : function($inputKey) {
+ /**
+ * Check if any user string inputs has illegal characters that jso=
n cannot accept
+ */
+ if ($inputKey.val().search(/"|'|\\/) !=3D=3D -1){
+ alert("Named fields cannot contain these illegal characters: d=
ouble quote(\"), single guote(\'), or back slash(\\). ");
+ return true;
+ }
+ return false;
+ }
+});
+
+
+function PhyloTreeLayout() {
+ /**
+ * -- Custom Layout call for phyloViz to suit the needs of a phylogene=
tic tree.
+ * -- Specifically: 1) Nodes have a display display of (=3D evo dist X=
depth separation) from their parent
+ * 2) Nodes must appear in other after they have expa=
nd and contracted
+ */
+
+ var self =3D this,
+ hierarchy =3D d3.layout.hierarchy().sort(null).value(null),
+ height =3D 360, // ! represents both the layout angle and the heig=
ht of the layout, in px
+ layoutMode =3D "Linear",
+ leafHeight =3D 18, // height of each individual leaf node
+ depthSeparation =3D 200, // separation between nodes of different =
depth, in px
+ leafIndex =3D 0, // change to recurssive call
+ defaultDist =3D 0.5, // tree defaults to 0.5 dist if no dist is sp=
ecified
+ maxTextWidth =3D 50; // maximum length of the text labels
+
+
+ self.leafHeight =3D function(inputLeafHeight){
+ if (typeof inputLeafHeight =3D=3D=3D "undefined"){ return leafHeig=
ht; }
+ else { leafHeight =3D inputLeafHeight; return self;}
+ };
+
+ self.layoutMode =3D function(mode){
+ if (typeof mode =3D=3D=3D "undefined"){ return layoutMode; }
+ else { layoutMode =3D mode; return self;}
+ };
+
+ self.layoutAngle =3D function(angle) { // changes the layout angle =
of the display, which is really changing the height
+ if (typeof angle =3D=3D=3D "undefined"){ return height; }
+ if (isNaN(angle) || angle < 0 || angle > 360) { return self; } // =
to use default if the user puts in strange values
+ else { height =3D angle; return self;}
+ };
+
+ self.separation =3D function(dist){ // changes the dist between the =
nodes of different depth
+ if (typeof dist =3D=3D=3D "undefined"){ return depthSeparation; }
+ else { depthSeparation =3D dist; return self;}
+ };
+
+ self.links =3D function (nodes) { // uses d3 native method to gene=
rate links. Done.
+ return d3.layout.tree().links(nodes);
+ };
+
+ // -- Custom method for laying out phylogeny tree in a linear fashion
+ self.nodes =3D function (d, i) {
+ var _nodes =3D hierarchy.call(self, d, i), // self is to f=
ind the depth of all the nodes, assumes root is passed in
+ nodes =3D [],
+ maxDepth =3D 0,
+ numLeaves =3D 0;
+
+ // changing from hierarchy's custom format for data to usable form=
at
+ _nodes.forEach(function (_node){
+ var node =3D _node.data;
+ node.depth =3D _node.depth;
+ maxDepth =3D node.depth > maxDepth ? node.depth : maxDepth; /=
/finding max depth of tree
+ nodes.push(node);
+ });
+ // counting the number of leaf nodes and assigning max depth to no=
des that do not have children to flush all the leave nodes
+ nodes.forEach(function(node){
+ if ( !node.children ) { //&& !node._children
+ numLeaves +=3D 1;
+ node.depth =3D maxDepth; // if a leaf has no child it woul=
d be assigned max depth
+ }
+ });
+
+ leafHeight =3D layoutMode =3D=3D=3D "Circular" ? height / numLeave=
s : leafHeight;
+ leafIndex =3D 0;
+ layout(nodes[0], maxDepth, leafHeight, null);
+
+ return nodes;
+ };
+
+
+ function layout (node, maxDepth, vertSeparation, parent) {
+ /**
+ * -- Function with side effect of adding x0, y0 to all child; tak=
e in the root as starting point
+ * assuming that the leave nodes would be sorted in presented ord=
er
+ * horizontal(y0) is calculated according to (=3D evo dis=
t X depth separation) from their parent
+ * vertical (x0) - if leave node: find its order in all o=
f the leave node =3D=3D=3D node.id, then multiply by verticalSeparation
+ * - if parent node: is place in the mid point al=
l of its children nodes
+ * -- The layout will first calculate the y0 field going towards t=
he leaves, and x0 when returning
+ */
+ var children =3D node.children,
+ sumChildVertSeparation =3D 0;
+
+ // calculation of node's dist from parents, going down.
+ var dist =3D node.dist || defaultDist;
+ dist =3D dist > 1 ? 1 : dist; // We constrain all dist to be l=
ess than one
+ node.dist =3D dist;
+ if (parent !=3D=3D null){
+ node.y0 =3D parent.y0 + dist * depthSeparation;
+ } else { //root node
+ node.y0 =3D maxTextWidth;
+ }
+
+
+ // if a node have no children, we will treat it as a leaf and star=
t laying it out first
+ if (!children) {
+ node.x0 =3D leafIndex++ * vertSeparation;
+ } else {
+ // if it has children, we will visit all its children and calc=
ulate its position from its children
+ children.forEach( function (child) {
+ child.parent =3D node;
+ sumChildVertSeparation +=3D layout(child, maxDepth, vertSe=
paration, node);
+ });
+ node.x0 =3D sumChildVertSeparation / children.length;
+ }
+
+ // adding properties to the newly created node
+ node.x =3D node.x0;
+ node.y =3D node.y0;
+ return node.x0;
+ }
+ return self;
+}
+
+
+/**
+ * -- PhyloTree Model --
+ */
+var PhyloTree =3D Visualization.extend({
+ defaults : {
+ layout: "Linear",
+ separation : 250, // px dist between nodes of different depth t=
o represent 1 evolutionary until
+ leafHeight: 18,
+ type : "phyloviz", // visualization type
+ title : "Title",
+ scaleFactor: 1,
+ translate: [0,0],
+ fontSize: 12, //fontSize of node label
+ selectedNode : null,
+ nodeAttrChangedTime : 0
+ },
+
+ root : {}, // Root has to be its own independent object because it is =
not part of the viz_config
+
+ toggle : function (d) {
+ /**
+ * Mechanism to expand or contract a single node. Expanded nodes h=
ave a children list, while for
+ * contracted nodes the list is stored in _children. Nodes with th=
eir children data stored in _children will not have their
+ * children rendered.
+ */
+ if(typeof d =3D=3D=3D "undefined") {return ;}
+ if (d.children ) {
+ d._children =3D d.children;
+ d.children =3D null;
+ } else {
+ d.children =3D d._children;
+ d._children =3D null;
+ }
+ },
+
+ toggleAll : function(d) {
+ /**
+ * Contracts the phylotree to a single node by repeatedly calling=
itself to place all the list
+ * of children under _children.
+ */
+ if (d.children && d.children.length !=3D=3D 0) {
+ d.children.forEach(this.toggleAll);
+ toggle(d);
+ }
+ },
+
+ getData : function (){
+ /**
+ * Return the data of the tree. Used for preserving state.
+ */
+ return this.root;
+ },
+
+ save: function() {
+ /**
+ * Overriding the default save mechanism to do some clean of circu=
lar reference of the
+ * phyloTree and to include phyloTree in the saved json
+ */
+ var root =3D this.root;
+ cleanTree(root);
+ this.set("root", root);
+
+ function cleanTree(node){
+ // we need to remove parent to delete circular reference
+ delete node.parent;
+
+ // removing unnecessary attributes
+ if (node._selected){ delete node._selected;}
+
+ node.children ? node.children.forEach(cleanTree) : 0;
+ node._children ? node._children.forEach(cleanTree) : 0;
+ }
+
+ var config =3D jQuery.extend(true, {}, this.attributes);
+ config["selectedNode"] =3D null;
+
+ show_message("Saving to Galaxy", "progress");
+
+ return $.ajax({
+ url: this.url(),
+ type: "POST",
+ dataType: "json",
+ data: {
+ vis_json: JSON.stringify(config)
+ },
+ success: function(res){
+ var viz_id =3D res.url.split("id=3D")[1].split("&")[0],
+ viz_url =3D "/phyloviz/visualization?id=3D" + viz_id;
+ window.history.pushState({}, "", viz_url + window.location=
.hash);
+ hide_modal();
+ }
+ });
+ }
+});
+
+
+
+/**
+ * -- Views --
+ */
+var PhylovizLayoutBase =3D Backbone.View.extend({
+ /**
+ * Stores the default variable for setting up the visualization
+ */
+ defaults : {
+ nodeRadius : 4.5 // radius of each node in the diagram
+ },
+
+
+ stdInit : function (options) {
+ /**
+ * Common initialization in layouts
+ */
+
+ var self =3D this;
+ self.model.on("change:separation change:leafHeight change:fontSize=
change:nodeAttrChangedTime", self.updateAndRender, self);
+
+ self.vis =3D options.vis;
+ self.i =3D 0;
+ self.maxDepth =3D -1; // stores the max depth of the tree
+
+ self.width =3D options.width;
+ self.height =3D options.height;
+ },
+
+
+ updateAndRender : function(source) {
+ /**
+ * Updates the visualization whenever there are changes in the ex=
pansion and contraction of nodes
+ * AND possibly when the tree is edited.
+ */
+ var vis =3D d3.select(".vis"),
+ self =3D this;
+ source =3D source || self.model.root;
+
+ self.renderNodes(source);
+ self.renderLinks(source);
+ self.addTooltips();
+ },
+
+
+ renderLinks : function(source) {
+ /**
+ * Renders the links for the visualization.
+ */
+ var self =3D this;
+ var diagonal =3D self.diagonal;
+ var duration =3D self.duration;
+ var layoutMode =3D self.layoutMode;
+ var link =3D self.vis.selectAll("g.completeLink")
+ .data(self.tree.links(self.nodes), function(d) { return d.targ=
et.id; });
+
+ var calcalateLinePos =3D function(d) {
+ d.pos0 =3D d.source.y0 + " " + d.source.x0; // position of t=
he source node <=3D> starting location of the line drawn
+ d.pos1 =3D d.source.y0 + " " + d.target.x0; // position where=
the line makes a right angle bend
+ d.pos2 =3D d.target.y0 + " " + d.target.x0; // point where=
the horizontal line becomes a dotted line
+ };
+
+ var linkEnter =3D link.enter().insert("svg:g","g.node")
+ .attr("class", "completeLink");
+
+
+ linkEnter.append("svg:path")
+ .attr("class", "link")
+ .attr("d", function(d) {
+ calcalateLinePos(d);
+ return "M " + d.pos0 + " L " + d.pos1;
+ });
+
+ var linkUpdate =3D link.transition().duration(500);
+
+ linkUpdate.select("path.link")
+ .attr("d", function(d) {
+ calcalateLinePos(d);
+ return "M " + d.pos0 + " L " + d.pos1 + " L " + d.pos2;
+ });
+
+ var linkExit =3D link.exit().remove();
+
+ },
+
+ // User Interaction methods below
+
+ selectNode : function(node){
+ /**
+ * Displays the information for editting
+ */
+ var self =3D this;
+ d3.selectAll("g.node")
+ .classed("selectedHighlight", function(d){
+ if (node.id =3D=3D=3D d.id){
+ if(node._selected) { // for de=3Dselecting node.
+ delete node._selected;
+ return false;
+ } else {
+ node._selected =3D true;
+ return true;
+ }
+ }
+ return false;
+ });
+
+ self.model.set("selectedNode", node);
+ $("#phyloVizSelectedNodeName").val(node.name);
+ $("#phyloVizSelectedNodeDist").val(node.dist);
+ $("#phyloVizSelectedNodeAnnotation").val(node.annotation || "");
+ },
+
+ addTooltips : function (){
+ /**
+ * Creates bootstrap tooltip for the visualization. Has to be cal=
led repeatedly due to newly generated
+ * enterNodes
+ */
+ $(".bs-tooltip").remove(); //clean up tooltip, just in case i=
ts listeners are removed by d3
+ $(".node")
+ .attr("data-original-title", function(){
+ var d =3D this.__data__,
+ annotation =3D d.annotation || "None" ;
+ return d ? (d.name ? d.name + "<br/>" : "") + "Dist: " + d=
.dist + " <br/>Annotation: " + annotation: "";
+ })
+ .tooltip({'placement':'top', 'trigger' : 'hover'});
+
+ }
+});
+
+
+
+
+var PhylovizLinearView =3D PhylovizLayoutBase.extend({
+ /**
+ * Linea layout class of Phyloviz, is responsible for rendering the no=
des
+ * calls PhyloTreeLayout to determine the positions of the nodes
+ */
+ initialize : function(options){
+ // Default values of linear layout
+ var self =3D this;
+ self.margins =3D options.margins;
+ self.layoutMode =3D "Linear";
+
+ self.stdInit(options);
+
+ self.layout();
+ self.updateAndRender(self.model.root);
+ },
+
+ layout : function() {
+ /**
+ * Creates the basic layout of a linear tree by precalculating fix=
ed values.
+ * One of calculations are also made here
+ */
+
+ var self =3D this;
+
+ self.tree =3D new PhyloTreeLayout().layoutMode("Linear");
+ self.diagonal =3D d3.svg.diagonal()
+ .projection(function(d) { return [d.y, d.x ]; });
+ },
+
+ renderNodes : function (source) {
+ /**
+ * Renders the nodes base on Linear layout.
+ */
+ var self =3D this,
+ fontSize =3D self.model.get("fontSize") + "px";
+
+ // assigning properties from models
+ self.tree.separation(self.model.get("separation")).leafHeight(self=
.model.get("leafHeight"));
+
+ var duration =3D 500,
+ nodes =3D self.tree.separation(self.model.get("separation")).n=
odes(self.model.root);
+
+ var node =3D self.vis.selectAll("g.node")
+ .data(nodes, function(d) { return d.name + d.id || (d.id =3D +=
+self.i); });
+
+ // These variables has to be passed into update links which are in=
the base methods
+ self.nodes =3D nodes;
+ self.duration =3D duration;
+
+ // ------- D3 ENTRY --------
+ // Enter any new nodes at the parent's previous position.
+ var nodeEnter =3D node.enter().append("svg:g")
+ .attr("class", "node")
+ .on("dblclick", function(){ d3.event.stopPropagation(); })
+ .on("click", function(d) {
+ if (d3.event.altKey) {
+ self.selectNode(d); // display info if alt is p=
ressed
+ } else {
+ if(d.children && d.children.length =3D=3D=3D 0){ retur=
n;} // there is no need to toggle leaves
+ self.model.toggle(d); // contract/expand nodes at da=
ta level
+ self.updateAndRender(d); // re-render the tree
+ }
+ });
+
+ nodeEnter.attr("transform", function(d) { return "translate(" + so=
urce.y0 + "," + source.x0 + ")"; });
+
+ nodeEnter.append("svg:circle")
+ .attr("r", 1e-6)
+ .style("fill", function(d) { return d._children ? "lightsteelb=
lue" : "#fff"; });
+
+ nodeEnter.append("svg:text")
+ .attr("class", "nodeLabel")
+ .attr("x", function(d) { return d.children || d._children ? -1=
0 : 10; })
+ .attr("dy", ".35em")
+ .attr("text-anchor", function(d) { return d.children || d._chi=
ldren ? "end" : "start"; })
+ .style("fill-opacity", 1e-6);
+
+ // ------- D3 TRANSITION --------
+ // Transition nodes to their new position.
+ var nodeUpdate =3D node.transition()
+ .duration(duration);
+
+ nodeUpdate.attr("transform", function(d) {
+ return "translate(" + d.y + "," + d.x + ")"; });
+
+ nodeUpdate.select("circle")
+ .attr("r", self.defaults.nodeRadius)
+ .style("fill", function(d) { return d._children ? "lightsteelb=
lue" : "#fff"; });
+
+ nodeUpdate.select("text")
+ .style("fill-opacity", 1)
+ .style("font-size", fontSize)
+ .text(function(d) { return d.name; });
+
+ // ------- D3 EXIT --------
+ // Transition exiting nodes to the parent's new position.
+ var nodeExit =3Dnode.exit().transition()
+ .duration(duration)
+ .remove();
+
+ nodeExit.select("circle")
+ .attr("r", 1e-6);
+
+ nodeExit.select("text")
+ .style("fill-opacity", 1e-6);
+
+ // Stash the old positions for transition.
+ nodes.forEach(function(d) {
+ d.x0 =3D d.x; // we need the x0, y0 for parents with children
+ d.y0 =3D d.y;
+ });
+ }
+
+});
+
+var PhylovizView =3D Backbone.View.extend({
+
+ className: 'phyloviz',
+
+ initialize: function(options) {
+ var self =3D this;
+ // -- Default values of the vis
+ self.MIN_SCALE =3D 0.05; //for zooming
+ self.MAX_SCALE =3D 5;
+ self.MAX_DISPLACEMENT =3D 500;
+ self.margins =3D [10, 60, 10, 80];
+
+ self.width =3D $("#PhyloViz").width();
+ self.height =3D $("#PhyloViz").height();
+ self.radius =3D self.width;
+ self.data =3D options.data;
+
+ // -- Events Phyloviz view responses to
+ $(window).resize(function(){
+ self.width =3D $("#PhyloViz").width();
+ self.height =3D $("#PhyloViz").height();
+ self.render();
+ });
+
+ // -- Create phyloTree model
+ self.phyloTree =3D new PhyloTree(options.config);
+ self.phyloTree.root =3D self.data;
+
+ // -- Set up UI functions of main view
+ self.zoomFunc =3D d3.behavior.zoom().scaleExtent([self.MIN_SCALE, =
self.MAX_SCALE]);
+ self.zoomFunc.translate(self.phyloTree.get("translate"));
+ self.zoomFunc.scale(self.phyloTree.get("scaleFactor"));
+
+ // -- set up header buttons, search and settings menu
+ self.navMenu =3D new HeaderButtons(self);
+ self.settingsMenu =3D new SettingsMenu({phyloTree : self.phyloTree=
});
+ self.nodeSelectionView =3D new NodeSelectionView({phyloTree : self=
.phyloTree});
+ self.search =3D new PhyloVizSearch();
+
+
+ setTimeout(function(){ // using settimeout to call the zoomAn=
dPan function according to the stored attributes in viz_config
+ self.zoomAndPan();
+ }, 1000);
+ },
+
+ render: function(){
+ // -- Creating helper function for vis. --
+ var self =3D this;
+ $("#PhyloViz").empty();
+
+ // -- Layout viz. --
+ self.mainSVG =3D d3.select("#PhyloViz").append("svg:svg")
+ .attr("width", self.width)
+ .attr("height", self.height)
+ .attr("pointer-events", "all")
+ .call(self.zoomFunc.on("zoom", function(){
+ self.zoomAndPan();
+ }));
+
+ self.boundingRect =3D self.mainSVG.append("svg:rect")
+ .attr("class", "boundingRect")
+ .attr("width", self.width)
+ .attr("height", self.height)
+ .attr("stroke", "black")
+ .attr("fill", "white");
+
+ self.vis =3D self.mainSVG
+ .append("svg:g")
+ .attr("class", "vis");
+
+ self.layoutOptions =3D {
+ model : self.phyloTree,
+ width : self.width,
+ height : self.height,
+ vis: self.vis,
+ margins: self.margins
+ };
+
+ // -- Creating Title
+ $("#title").text("Phylogenetic Tree from " + self.phyloTree.get("t=
itle") + ":");
+
+ // -- Create Linear view instance --
+ var linearView =3D new PhylovizLinearView(self.layoutOptions)
+ },
+
+ zoomAndPan : function(event){
+ /**
+ * 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 an=
d keeping states in model
+ */
+ if (typeof event !=3D=3D "undefined") {
+ var zoomParams =3D event.zoom,
+ translateParams =3D event.translate;
+ }
+
+ var self =3D this,
+ scaleFactor =3D self.zoomFunc.scale(),
+ translationCoor =3D self.zoomFunc.translate(),
+ zoomStatement =3D "",
+ translateStatement =3D "";
+
+ // Do manual scaling.
+ switch (zoomParams) {
+ case "reset":
+ scaleFactor =3D 1.0;
+ translationCoor =3D [0,0]; break;
+ case "+":
+ scaleFactor *=3D 1.1; break;
+ case "-":
+ scaleFactor *=3D 0.9; break;
+ default:
+ if (typeof zoomParams =3D=3D=3D "number") {
+ scaleFactor =3D zoomParams;
+ } else if (d3.event !=3D=3D null) {
+ scaleFactor =3D d3.event.scale;
+ }
+ }
+ if (scaleFactor < self.MIN_SCALE || scaleFactor > self.MAX_SCALE) =
{ return;}
+ self.zoomFunc.scale(scaleFactor); //update scale Factor
+ zoomStatement =3D "translate(" + self.margins[3] + "," + self.mar=
gins[0] + ")" +
+ " scale(" + scaleFactor + ")";
+
+ // Do manual translation.
+ if( d3.event !=3D=3D null) {
+ translateStatement =3D "translate(" + d3.event.translate + ")";
+ } else {
+ if(typeof translateParams !=3D=3D "undefined") {
+ var x =3D translateParams.split(",")[0];
+ var y =3D translateParams.split(",")[1];
+ if (!isNaN(x) && !isNaN(y)){
+ translationCoor =3D [translationCoor[0] + parseFloat(x=
), translationCoor[1] + parseFloat(y)];
+ }
+ }
+ self.zoomFunc.translate(translationCoor); // update zoomFunc
+ translateStatement =3D "translate(" + translationCoor + ")";
+ }
+
+ self.phyloTree.set("scaleFactor", scaleFactor);
+ self.phyloTree.set("translate", translationCoor);
+ self.vis.attr("transform", translateStatement + zoomStatement); //=
refers to the view that we are actually zooming
+ },
+
+
+ reloadViz : function() {
+ /**
+ * Primes the Ajax URL to load another Nexus tree
+ */
+ var self =3D this,
+ treeIndex =3D $("#phylovizNexSelector :selected").val(),
+ dataset_id =3D self.phyloTree.get("dataset_id"),
+ url =3D "phyloviz/getJsonData?dataset_id=3D" + dataset_id + "&=
treeIndex=3D" + String(treeIndex);
+ $.getJSON(url, function(packedJson){
+ window.initPhyloViz(packedJson.data, packedJson.config);
+ });
+ }
+});
+
+
+var HeaderButtons =3D Backbone.View.extend({
+
+ initialize : function(phylovizView){
+ var self =3D this;
+ self.phylovizView =3D phylovizView;
+
+ // Clean up code - if the class initialized more than once
+ $("#panelHeaderRightBtns").empty();
+ $("#phyloVizNavBtns").empty();
+ $("#phylovizNexSelector").off();
+
+ self.initNavBtns();
+ self.initRightHeaderBtns();
+
+ // Initial a tree selector in the case of nexus
+ $("#phylovizNexSelector").off().on("change", function() {self.phy=
lovizView.reloadViz();} );
+
+ },
+
+ initRightHeaderBtns : function(){
+ var self =3D this;
+
+ rightMenu =3D create_icon_buttons_menu([
+ { icon_class: 'gear', title: 'PhyloViz Settings', on_click: fu=
nction(){
+ $("#SettingsMenu").show();
+ self.settingsMenu.updateUI();
+ } },
+ { icon_class: 'disk', title: 'Save visualization', on_click: f=
unction() {
+ var nexSelected =3D $("#phylovizNexSelector option:selecte=
d").text();
+ if(nexSelected) {
+ self.phylovizView.phyloTree.set("title", nexSelected);
+ }
+ self.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');
+ // https://docs.google.com/document/d/1AXFoJgEpxr21H3LICRs=
3EyMe1B1X_KFPouzIgrCz3zk/edit
+ } }
+ ],
+ {
+ tooltip_config: { placement: 'bottom' }
+ });
+ $("#panelHeaderRightBtns").append(rightMenu.$el);
+ },
+
+ initNavBtns: function() {
+ var self =3D this,
+ navMenu =3D create_icon_buttons_menu([
+ { icon_class: 'zoom-in', title: 'Zoom in', on_click: funct=
ion() {
+ self.phylovizView.zoomAndPan({ zoom : "+"});
+ } },
+ { icon_class: 'zoom-out', title: 'Zoom out', on_click: fun=
ction() {
+ self.phylovizView.zoomAndPan({ zoom : "-"});
+ } },
+ { icon_class: 'arrow-circle', title: 'Reset Zoom/Pan', on_=
click: function() {
+ self.phylovizView.zoomAndPan({ zoom : "reset"});
+ } }
+ ],
+ {
+ tooltip_config: { placement: 'bottom' }
+ });
+ $("#phyloVizNavBtns").append(navMenu.$el);
+ }
+});
+
+
+var SettingsMenu =3D UserMenuBase.extend({
+
+ className: 'Settings',
+
+ initialize: function(options){
+ // settings needs to directly interact with the phyloviz model so =
it will get access to it.
+ var self =3D this;
+ self.phyloTree =3D options.phyloTree;
+ self.el =3D $("#SettingsMenu");
+ self.inputs =3D {
+ separation : $("#phyloVizTreeSeparation"),
+ leafHeight : $("#phyloVizTreeLeafHeight"),
+ fontSize : $("#phyloVizTreeFontSize")
+ };
+
+ //init all buttons of settings
+ $("#settingsCloseBtn").off().on("click", function() { self.el.hide=
(); });
+ $("#phylovizResetSettingsBtn").off().on("click", function() { self=
.resetToDefaults(); });
+ $("#phylovizApplySettingsBtn").off().on("click", function() { self=
.apply(); });
+ },
+
+ apply : function(){
+ /**
+ * Applying user values to phylotree model.
+ */
+ var self =3D this;
+ 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){
+ self.phyloTree.set(key, $input.val());
+ });
+ },
+ updateUI : function(){
+ /**
+ * Called to update the values input to that stored in the model
+ */
+ var self =3D this;
+ $.each(self.inputs, function(key, $input){
+ $input.val(self.phyloTree.get(key));
+ });
+ },
+ resetToDefaults : function(){
+ /**
+ * Resets the value of the phyloTree model to its default
+ */
+ $(".bs-tooltip").remove(); // just in case the tool tip was n=
ot removed
+ var self =3D this;
+ $.each(self.phyloTree.defaults, function(key, value) {
+ self.phyloTree.set(key, value);
+ });
+ self.updateUI();
+ },
+
+ render: function(){
+
+ }
+
+});
+
+
+var NodeSelectionView =3D UserMenuBase.extend({
+ /**
+ * View for inspecting node properties and editing them
+ */
+ className: 'Settings',
+
+ initialize : function (options){
+ var self =3D this;
+ self.el =3D $("#nodeSelectionView");
+ self.phyloTree =3D options.phyloTree;
+
+ self.UI =3D {
+ enableEdit : $('#phylovizEditNodesCheck'),
+ saveChanges : $('#phylovizNodeSaveChanges'),
+ cancelChanges : $("#phylovizNodeCancelChanges"),
+ name : $("#phyloVizSelectedNodeName"),
+ dist : $("#phyloVizSelectedNodeDist"),
+ annotation : $("#phyloVizSelectedNodeAnnotation")
+ };
+
+ self.valuesOfConcern =3D {
+ name : null,
+ dist : null,
+ annotation : null
+ }; // temporarily stores the values in case user change their mind
+
+ //init UI buttons
+ $("#nodeSelCloseBtn").off().on("click", function() { self.el.hide(=
); });
+ self.UI.saveChanges.off().on("click", function(){ self.updateNodes=
(); });
+ self.UI.cancelChanges.off().on("click", function(){ self.cancelCha=
nges(); });
+
+ (function ($) {
+ // extending jquery fxn for enabling and disabling nodes.
+ $.fn.enable =3D function (isEnabled) {
+ return $(this).each(function () {
+ if(isEnabled){
+ $(this).removeAttr('disabled');
+ } else {
+ $(this).attr('disabled', 'disabled');
+ }
+ });
+ };
+ })(jQuery);
+
+ self.UI.enableEdit.off().on("click", function () {
+ self.toggleUI();
+ });
+ },
+
+ toggleUI : function(){
+ /**
+ * For turning on and off the child elements
+ */
+ var self =3D this,
+ checked =3D self.UI.enableEdit.is(':checked');
+
+ !checked ? self.cancelChanges() : "";
+
+ $.each(self.valuesOfConcern, function(key, value) {
+ self.UI[key].enable(checked);
+ });
+ if(checked){
+ self.UI.saveChanges.show();
+ self.UI.cancelChanges.show();
+ } else {
+ self.UI.saveChanges.hide();
+ self.UI.cancelChanges.hide();
+ }
+
+ },
+
+ cancelChanges : function() {
+ /**
+ * Reverting to previous values in case user change their minds
+ */
+ var self =3D this,
+ node =3D self.phyloTree.get("selectedNode");
+ if (node){
+ $.each(self.valuesOfConcern, function(key, value) {
+ self.UI[key].val(node[key]);
+ });
+ }
+ },
+
+ updateNodes : function (){
+ /**
+ * Changing the data in the underlying tree with user-specified va=
lues
+ */
+ var self =3D this,
+ node =3D self.phyloTree.get("selectedNode");
+ if (node){
+ if (!self.isAcceptableValue(self.UI.dist, 0, 1) ||
+ self.hasIllegalJsonCharacters(self.UI.name) ||
+ self.hasIllegalJsonCharacters(self.UI.annotation) ) {
+ return;
+ }
+ $.each(self.valuesOfConcern, function(key, value) {
+ (node[key]) =3D self.UI[key].val();
+ });
+ self.phyloTree.set("nodeAttrChangedTime", new Date());
+ } else {
+ alert("No node selected");
+ }
+ }
+
+
+});
+
+
+
+var PhyloVizSearch =3D UserMenuBase.extend({
+ /**
+ * Initializes the search panel on phyloviz and handles its user inter=
action
+ * It allows user to search the entire free based on some qualifer, li=
ke dist <=3D val.
+ */
+ initialize : function () {
+ var self =3D this;
+
+ $("#phyloVizSearchBtn").on("click", function(){
+ var searchTerm =3D $("#phyloVizSearchTerm"),
+ searchConditionVal =3D $("#phyloVizSearchCondition").val()=
.split("-"),
+ attr =3D searchConditionVal[0],
+ condition =3D searchConditionVal[1];
+ self.hasIllegalJsonCharacters(searchTerm);
+
+ if (attr =3D=3D=3D "dist"){
+ self.isAcceptableValue(searchTerm, 0, 1);
+ }
+ self.searchTree(attr, condition, searchTerm.val());
+ });
+ },
+
+ searchTree : function (attr, condition, val){
+ /**
+ * Searches the entire tree and will highlight the nodes that matc=
h the condition in green
+ */
+ d3.selectAll("g.node")
+ .classed("searchHighlight", function(d){
+ var attrVal =3D d[attr];
+ if (typeof attrVal !=3D=3D "undefined" && attrVal !=3D=3D =
null){
+ if (attr =3D=3D=3D "dist"){
+ switch (condition) {
+ case "greaterEqual":
+ return attrVal >=3D +val;
+ case "lesserEqual":
+ return attrVal <=3D +val;
+ default:
+ return;
+ }
+
+ } else if (attr =3D=3D=3D "name" || attr =3D=3D=3D "an=
notation") {
+ return attrVal.toLowerCase().indexOf(val.toLowerCa=
se()) !=3D=3D -1;
+ }
+ }
+ });
+ }
+});
\ No newline at end of file
diff -r 89dbce43ba88afdc3e6265feea7e7e042bb030a7 -r 75a03bacdc7a3dc5b1c03f8=
b02df0ab383366955 templates/root/history.mako
--- a/templates/root/history.mako
+++ b/templates/root/history.mako
@@ -272,6 +272,17 @@
}
=20
init_trackster_links();
+
+ function init_phyloviz_links() {
+ // PhyloViz links
+ // Add to trackster browser functionality
+ $(".phyloviz-add").live("click", function() {
+ var dataset =3D this,
+ dataset_jquery =3D $(this);
+ window.parent.location =3D dataset_jquery.attr("new-url");
+ });
+ }
+ init_phyloviz_links();
=20
// History rename functionality.
async_save_text("history-name-container", "history-name", "${h.url_for=
( controller=3D"/history", action=3D"rename_async", id=3Dtrans.security.enc=
ode_id(history.id) )}", "new_name", 18);
diff -r 89dbce43ba88afdc3e6265feea7e7e042bb030a7 -r 75a03bacdc7a3dc5b1c03f8=
b02df0ab383366955 templates/root/history_common.mako
--- a/templates/root/history_common.mako
+++ b/templates/root/history_common.mako
@@ -29,6 +29,9 @@
## Render the dataset `data` as history item, using `hid` as the displayed=
id
<%def name=3D"render_dataset( data, hid, show_deleted_on_refresh =3D False=
, for_editing =3D True, display_structured =3D False )"><%
+
+ from galaxy.datatypes.xml import Phyloxml
+ from galaxy.datatypes.data import Newick, Nexus
dataset_id =3D trans.security.encode_id( data.id )
=20
if data.state in ['no state','',None]:
@@ -230,6 +233,14 @@
action-url=3D"${h.url_for( controller=3D't=
racks', action=3D'browser', dataset_id=3Ddataset_id)}"
new-url=3D"${h.url_for( controller=3D'trac=
ks', action=3D'index', dataset_id=3Ddataset_id, default_dbkey=3Ddata.dbkey)=
}" title=3D"View in Trackster"></a>
%endif
+ <%
+ isPhylogenyData =3D isinstance(data.datatype, =
(Phyloxml, Nexus, Newick))
+ %>
+ %if isPhylogenyData:
+ <a href=3D"javascript:void(0)" class=3D"i=
con-button chart_curve phyloviz-add"
+ action-url=3D"${h.url_for( controller=
=3D'phyloviz', action=3D'-', dataset_id=3Ddataset_id)}"
+ new-url=3D"${h.url_for( controller=3D'p=
hyloviz', action=3D'index', dataset_id=3Ddataset_id)}" title=3D"View in Phy=
loviz"></a>
+ %endif
%if trans.user:
%if not display_structured:
<div style=3D"float: right">
diff -r 89dbce43ba88afdc3e6265feea7e7e042bb030a7 -r 75a03bacdc7a3dc5b1c03f8=
b02df0ab383366955 templates/visualization/phyloviz.mako
--- /dev/null
+++ b/templates/visualization/phyloviz.mako
@@ -0,0 +1,320 @@
+<%inherit file=3D"/webapps/galaxy/base_panels.mako"/>
+##
+<%def name=3D"init()">
+ <%
+ self.has_left_panel=3DFalse
+ self.has_right_panel=3DFalse
+ self.active_view=3D"visualization"
+ self.message_box_visible=3DFalse
+ %>
+</%def>
+
+<%def name=3D"stylesheets()">
+ ${parent.stylesheets()}
+ <style>
+
+ .node circle {
+ cursor: pointer;
+ fill: #fff;
+ stroke: steelblue;
+ stroke-width: 1.5px;
+ }
+
+ .node.searchHighlight circle {
+ stroke-width: 3px;
+ stroke: #7adc26;
+ }
+
+ .node.selectedHighlight circle {
+ stroke-width: 3px;
+ stroke: #dc143c;
+ }
+
+ path.link {
+ fill: none;
+ stroke: #B5BBFF;
+ stroke-width: 4.0px;
+ }
+
+
+ div #phyloVizNavContainer{
+ text-align: center;
+ width: 100%;
+ height: 0px;
+ }
+
+ div #phyloVizNav{
+ font-weight: bold;
+ display: inline-block;
+ background: transparent;
+ top: -2em;
+ position: relative;
+ }
+
+ div .navControl{
+ float: left;
+ }
+
+ div#FloatingMenu {
+ left: 0;
+ top: 15%;
+ width:20%;
+ z-index:100;
+ padding: 5px;
+
+ }
+
+ div#SettingsMenu {
+ width: 25%;
+ top: 350px;
+
+ }
+
+ div#nodeSelectionView {
+ width: 25%;
+ top:70px;
+ }
+
+ .Panel {
+ right: 0%;
+ z-index: 101;
+ position: fixed;
+
+ ## Borrowed from galaxy modal_dialogues
+ background-color: white;
+ border: 1px solid #999;
+ border: 1px solid rgba(0, 0, 0, 0.3);
+ -webkit-border-radius: 6px;
+ -moz-border-radius: 6px;
+ border-radius: 6px;
+ -webkit-border-radius: 6px;
+ -moz-border-radius: 6px;
+ border-radius: 6px;
+ -webkit-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3);
+ -moz-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3);
+ box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3);
+ -webkit-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3);
+ -moz-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3);
+ box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3);
+ -webkit-background-clip: padding-box;
+ -moz-background-clip: padding-box;
+ background-clip: padding-box;
+ -webkit-background-clip: padding-box;
+ -moz-background-clip: padding-box;
+ background-clip: padding-box;
+ }
+
+ span.PhylovizCloseBtn{
+ cursor: pointer;
+ float : right;
+ }
+
+ #PhyloViz{
+ width: 100%;
+ height: 95%;
+ }
+
+ h2.PhyloVizMenuTitle{
+ color: white;
+ }
+
+ ## Settings Menu
+ .SettingMenuRows{
+ margin: 2px 0 2px 0;
+ }
+
+
+ ## Helper Styles
+ .PhyloVizFloatLeft{
+ float : left;
+ }
+ .icon-button.zoom-in,.icon-button.zoom-out{display:inline-block;he=
ight:16px;width:16px;margin-bottom:-3px;cursor:pointer;}
+ .icon-button.zoom-out{background:transparent url(../images/fugue/m=
agnifier-zoom-out.png) center center no-repeat;}
+ .icon-button.zoom-in{margin-left:10px;background:transparent url(.=
./images/fugue/magnifier-zoom.png) center center no-repeat;}
+
+ </style>
+</%def>
+
+
+<%def name=3D"javascripts()">
+ ${parent.javascripts()}
+ ${h.js( "galaxy.panels", "libs/d3", "mvc/data", "viz/visualization", "=
viz/phyloviz")}
+</%def>
+
+
+
+<%def name=3D"center_panel()">
+
+ <div class=3D"unified-panel-header" unselectable=3D"on">
+ <div class=3D"unified-panel-header-inner">
+ <div style=3D"float:left;" id=3D"title"></div>
+ <div style=3D"float:right;" id=3D"panelHeaderRightBtns"></div>
+ </div>
+ <div style=3D"clear: both"></div>
+ </div>
+
+
+ <div id=3D"phyloVizNavContainer">
+ <div id=3D"phyloVizNav">
+ %if config["ext"] =3D=3D "nex" and not config["saved_visualiza=
tion"]:
+ <div id =3D "phylovizNexInfo" class=3D"navControl">
+ <p>Select a tree to view:
+ <select id=3D"phylovizNexSelector">
+ % for tree, index in config["trees"]:
+ <option value=3D"${index}">${tree}</option>
+ % endfor
+ </select>
+ </p>
+ </div>
+ %endif
+ <div id=3D"phyloVizNavBtns" class=3D"navControl">
+ </div>
+ <div class=3D"navControl">
+ <p> | Alt+click to select nodes</p>
+ </div>
+
+
+ </div>
+
+ </div>
+
+ ## Node Selection Menu
+ <div id=3D"nodeSelectionView" class=3D"Panel">
+ <div class=3D"modal-header">
+ <h3 class=3D"PhyloVizMenuTitle">Search / Edit Nodes :
+ <span class=3D"PhylovizCloseBtn" id=3D"nodeSelCloseBtn"> X=
</span>
+ </h3>
+ </div>
+
+ <div class=3D"modal-body">
+
+ <div class=3D"SettingMenuRows">
+ Search for nodes with:
+ <select id=3D"phyloVizSearchCondition" style=3D"width: 55%=
">
+ <option value=3D"name-containing">Name (containing)</o=
ption>
+ <option value=3D"annotation-containing">Annotation (co=
ntaining)</option>
+ <option value=3D"dist-greaterEqual">Distance (>=3D)</o=
ption>
+ <option value=3D"dist-lesserEqual">Distance (<=3D)</op=
tion>
+ </select>
+ <input type=3D"text" id=3D"phyloVizSearchTerm" value=3D"N=
one" size=3D"15" displayLabel=3D"Distance">
+
+ <div class=3D"SettingMenuRows" style=3D"text-align: center=
;">
+ <button id=3D"phyloVizSearchBtn" > Search! </button>
+ </div>
+ </div>
+
+ <br/>
+
+ <div class=3D"SettingMenuRows">
+ Name: <input type=3D"text" id=3D"phyloVizSelectedNodeName"=
value=3D"None" size=3D"15" disabled=3D"disabled" >
+ </div>
+ <div class=3D"SettingMenuRows">
+ Dist: <input type=3D"text" id=3D"phyloVizSelectedNodeDist"=
value=3D"None" size=3D"15" disabled=3D"disabled" displayLabel=3D"Distance">
+ </div>
+ <div class=3D"SettingMenuRows">
+ Annotation:
+ <textarea id=3D"phyloVizSelectedNodeAnnotation" disabled=
=3D"disabled" ></textarea>
+ </div>
+ <div class=3D"SettingMenuRows">
+ Edit: <input type=3D"checkbox" id=3D"phylovizEditNodesChec=
k" value=3D"You can put custom annotations here and it will be saved">
+ <button id=3D"phylovizNodeSaveChanges" style=3D"display: n=
one;"> Save edits</button>
+ <button id=3D"phylovizNodeCancelChanges" style=3D"display:=
none;"> Cancel</button>
+ </div>
+ </div>
+ </div>
+
+ ## Settings Menus
+ <div id=3D"SettingsMenu" class=3D"Panel">
+ <div class=3D"modal-header">
+ <h3 class=3D"PhyloVizMenuTitle">Phyloviz Settings:
+ <span class=3D"PhylovizCloseBtn" id=3D"settingsCloseBtn"> =
X </span>
+ </h3>
+ </div>
+ <div class=3D"modal-body">
+ <div class=3D"SettingMenuRows">
+ Phylogenetic Spacing (px per unit): <input id=3D"phyloVizT=
reeSeparation" type=3D"text" value=3D"250" size=3D"10" displayLabel=3D"Phyl=
ogenetic Separation"> (50-2500)
+ </div>
+ <div class=3D"SettingMenuRows">
+ Vertical Spacing (px): <input type=3D"text" id=3D"phyloViz=
TreeLeafHeight" value=3D"18" size=3D"10" displayLabel=3D"Vertical Spacing">=
(5-30)
+ </div>
+ <div class=3D"SettingMenuRows">
+ Font Size (px): <input type=3D"text" id=3D"phyloVizTreeFon=
tSize" value=3D"12" size=3D"4" displayLabel=3D"Font Size"> (5-20)
+ </div>
+
+ </div>
+ <div class=3D"modal-footer">
+ <button id=3D"phylovizResetSettingsBtn" class=3D"PhyloVizFloat=
Left" > Reset </button>
+ <button id=3D"phylovizApplySettingsBtn" class=3D"PhyloVizFloat=
Right" > Apply </button>
+ </div>
+ </div>
+
+
+
+
+
+
+ <div class=3D"Panel" id=3D"FloatingMenu" style=3D"display: None;">
+
+ <h2>PhyloViz (<a onclick=3D"displayHelp()" href=3D"javascript:void=
(0);">?</a>)</h2>
+ <div style=3D"display: none;">
+ <h2>Summary of Interactions and Functions:</h2>
+ <div class=3D"hint">1. Expansion of Nodes: click or option-cli=
ck to expand or collapse</div>
+ <div class=3D"hint">2. Zooming and translation: mousewheel, bu=
ttons, click and drag, double click. Reset</div>
+ <div class=3D"hint">3. Tooltip: Displays "Name and Size" on mo=
useOver on nodes</div>
+ <div class=3D"hint">4. Minimap: Currently displays an exact bu=
t scaled down replicate of the tree, orange bounding box is correct for lin=
ear only<br/>
+ Can be switched on or off</div>
+ <div class=3D"hint">5. Changing Layouts: Able to change betwee=
n circular and linear layouts.</div>
+
+ </div>
+
+ <h5>Scaling & Rotation:</h5>
+ <button id=3D"phylovizZoomInBtn" class=3D"" > + </button>
+ <button id=3D"phylovizZoomOutBtn" class=3D"" > - </button>
+
+
+ <h5>Translation:</h5>
+ <button id=3D"phylovizTranslateUpBtn" > Up </button>
+ <button id=3D"phylovizTranslateDownBtn" > Down </button>
+ <br/>
+ <button id=3D"phylovizTranslateLeftBtn" > Left </button>
+ <button id=3D"phylovizTranslateRightBtn" > Right </button>
+
+
+
+ <h5>Others:</h5>
+ <button id=3D"phylovizResetBtn" > Reset Zoom/Translate </button>
+ <button id=3D"phylovizSaveBtn" > Save vizualization </button>
+ <button id=3D"phylovizOpenSettingsBtn" > Settings </button>
+ </div>
+
+ <div id=3D"PhyloViz" >
+ </div>
+
+ <script type=3D"text/javascript">
+
+ function initPhyloViz(data, config) {
+ var phyloviz;
+
+ // -- Initialization code |-->
+ phyloviz =3D new PhylovizView({
+ data: data,
+ layout : "Linear",
+ config : config
+ });
+
+ // -- Render viz. --
+ phyloviz.render();
+
+ }
+
+ $(function firstVizLoad(){ // calls when viz is loaded for t=
he first time
+ var config =3D JSON.parse( '${ h.to_json_string( config )}');
+ var data =3D JSON.parse('${h.to_json_string(data)}');
+ initPhyloViz(data, config);
+ });
+
+ </script>
+
+</%def>
+
+
diff -r 89dbce43ba88afdc3e6265feea7e7e042bb030a7 -r 75a03bacdc7a3dc5b1c03f8=
b02df0ab383366955 test-data/visualization/phyloviz/1_nexus.nex
--- /dev/null
+++ b/test-data/visualization/phyloviz/1_nexus.nex
@@ -0,0 +1,87 @@
+#NEXUS
+
+[!This data set was downloaded from TreeBASE, a relational database of phy=
logenetic knowledge. TreeBASE has been supported by the NSF, Harvard Univer=
sity, Yale University, SDSC and UC Davis. Please do not remove this acknowl=
edgment from the Nexus file.
+
+
+Generated on June 12, 2012; 23:00 GMT
+
+TreeBASE (cc) 1994-2008
+
+Study reference:
+Olariaga I., Grebenc T., Salcedo I., & Mart=C3=ADn M.P. 2012. Two new spec=
ies of Hydnum
+with ovoid basidiospores: H. ovoideisporum and H. vesterholtii. Mycologia,=
.
+
+TreeBASE Study URI: http://purl.org/phylo/treebase/phylows/study/TB2:S128=
31]
+
+BEGIN TREES;
+ TITLE Hydnum_ITS_result;
+ LINK TAXA =3D Taxa1;
+ TRANSLATE
+ 1 Hydnum_aff_ellipsosporum_RUFHYD1_AJ535304,
+ 2 Hydnum_albidum_ALB_AY817135,
+ 3 Hydnum_albidum_ALBHYD1_AJ534974,
+ 4 Hydnum_albomagnum_ALM_DQ218305,
+ 5 Hydnum_ellipsosporum_ELL_AY817138,
+ 6 Hydnum_ellipsosporum_RUFHYD8_AJ547882,
+ 7 Hydnum_ovoidisporum_12317BIOFungi,
+ 8 Hydnum_ovoidisporum_12683BIOFungi,
+ 9 Hydnum_ovoidisporum_12902BIOFungi,
+ 10 Hydnum_ovoidisporum_14130BIOFungi,
+ 11 Hydnum_repandum_RE1_REP1_AJ889978,
+ 12 Hydnum_repandum_RE1_REP2_AJ889949,
+ 13 Hydnum_repandum_RE1_REP3_AY817136,
+ 14 Hydnum_repandum_RE1_REP6_UDB000025,
+ 15 Hydnum_repandum_RE1_REP7_UDB000096,
+ 16 Hydnum_repandum_RE1_REP8_UDB001479,
+ 17 Hydnum_repandum_RE1_REPHYD10_AJ547888,
+ 18 Hydnum_repandum_RE1_REPHYD11_AJ547886,
+ 19 Hydnum_repandum_RE1_REPHYD1_AJ547871,
+ 20 Hydnum_repandum_RE1_REPHYD3_AJ547874,
+ 21 Hydnum_repandum_RE1_REPHYD4_AJ547876,
+ 22 Hydnum_repandum_RE1_REPHYD5_AJ547875,
+ 23 Hydnum_repandum_RE1_REPHYD6_AJ547877,
+ 24 Hydnum_repandum_RE1_REPHYD7_AJ547878,
+ 25 Hydnum_repandum_RE1_REPHYD8_AJ547881,
+ 26 Hydnum_repandum_RE1_REPHYD9_AJ547883,
+ 27 Hydnum_repandum_RE1_RUFHYD10_AJ547866,
+ 28 Hydnum_repandum_RE1_RUFHYD11_AJ547889,
+ 29 Hydnum_repandum_RE1_RUFHYD9_AJ535305,
+ 30 Hydnum_rufescens_RU1_RUFHYD5_AJ547869,
+ 31 Hydnum_rufescens_RU1_RUFHYD6_AJ547884,
+ 32 Hydnum_rufescens_RU1_RUFHYD7_AJ547870,
+ 33 Hydnum_rufescens_RU2_REP5_DQ367902,
+ 34 Hydnum_rufescens_RU2_RUFHYD2_AJ535301,
+ 35 Hydnum_rufescens_RU3_12901BIOFungi,
+ 36 Hydnum_rufescens_RU3_REP4_DQ218306,
+ 37 Hydnum_rufescens_RU3_RUFHYD3_AJ535303,
+ 38 Hydnum_rufescens_RU3_RUFHYD4_AJ535302,
+ 39 Hydnum_rufescens_RU4_RUFHYD12_AJ839969,
+ 40 Hydnum_rufescens_RU4_RUFHYD16_AJ547868,
+ 41 Hydnum_rufescens_RU4_RUFHYD17_AJ547885,
+ 42 Hydnum_rufescens_RU4_UMB1_DQ367903,
+ 43 Hydnum_rufescens_RU5_12760BIOFungi,
+ 44 Hydnum_rufescens_RU5_ALBHYD2_AJ534975,
+ 45 Hydnum_rufescens_RU5_RUF2_DQ658890,
+ 46 Hydnum_rufescens_RU5_RUF4_UDB001465,
+ 47 Hydnum_rufescens_RU5_RUF5_UDB002423,
+ 48 Hydnum_rufescens_RU5_RUFHYD14_AJ547872,
+ 49 Hydnum_rufescens_RU6_RUF1_AY817137,
+ 50 Hydnum_rufescens_RU6_RUFHYD15_AJ547867,
+ 51 Hydnum_rufescens_wrong_taxonomy_RUF3_AM087246,
+ 52 Hydnum_umbilicatum_UMBHYD1_AJ534972,
+ 53 Hydnum_umbilicatum_UMBHYD2_AJ534973,
+ 54 Hydnum_vesterholtii_10429BIOFungi,
+ 55 Hydnum_vesterholtii_10452BIOFungi,
+ 56 Hydnum_vesterholtii_12330BIOFungi,
+ 57 Hydnum_vesterholtii_12904BIOFungi,
+ 58 Hydnum_vesterholtii_REPHYD12A_AJ547879,
+ 59 Hydnum_vesterholtii_REPHYD12C_AJ783968,
+ 60 Hydnum_vesterholtii_REPHYD13_AJ547887,
+ 61 Sistotrema_muscicola_AJ606040,
+ 62 Sistotrema_alboluteum_AJ606042;
+ TREE Fig._2 =3D [&R] ((62:100.0,(51:100.0,61:100.0):93.269997):49.66=
,((4:100.0,(2:100.0,3:100.0):100.0):60.639999,(((56:100.0,58:100.0,59:100.0=
):84.639999,(54:100.0,55:100.0,57:100.0,60:100.0):98.330002):92.5,(((30:100=
.0,31:100.0,32:100.0):100.0,(11:100.0,12:100.0,13:100.0,14:100.0,15:100.0,1=
6:100.0,17:100.0,18:100.0,19:100.0,20:100.0,21:100.0,22:100.0,23:100.0,24:1=
00.0,25:100.0,26:100.0):99.93):68.690002,(((33:100.0,34:100.0):49.8050005,(=
35:100.0,36:100.0,37:100.0,38:100.0):99.989998):49.8050005,((7:100.0,8:100.=
0,9:100.0,10:100.0):100.0,(42:100.0,(39:100.0,40:100.0,41:100.0):98.449997)=
:86.790001,((52:100.0,53:100.0):99.93,(1:100.0,(5:97.47999949999999,6:100.0=
):97.47999949999999):100.0):53.310001,(27:100.0,(28:100.0,29:100.0,49:100.0=
,50:100.0):47.404999):47.404999,(43:100.0,44:100.0,45:100.0,46:100.0,47:100=
.0,48:100.0):99.459999):29.245001):29.245001):51.580002):61.540001):49.66);
+ TREE PAUP_1 =3D [&R] ((62:100.0,(51:100.0,61:100.0):93.269997):49.66=
,((4:100.0,(3:100.0,2:100.0):100.0):60.639999,(((58:100.0,59:100.0,56:100.0=
):84.639999,(60:100.0,54:100.0,55:100.0,57:100.0):98.330002):92.5,(((30:100=
.0,31:100.0,32:100.0):100.0,(19:100.0,20:100.0,21:100.0,22:100.0,23:100.0,2=
4:100.0,25:100.0,26:100.0,17:100.0,18:100.0,11:100.0,12:100.0,13:100.0,14:1=
00.0,15:100.0,16:100.0):99.93):68.690002,((34:100.0,33:100.0):99.610001,(37=
:100.0,38:100.0,35:100.0,36:100.0):99.989998,(42:100.0,(39:100.0,41:100.0,4=
0:100.0):98.449997):86.790001,(8:100.0,7:100.0,9:100.0,10:100.0):100.0,((52=
:100.0,53:100.0):99.93,(1:100.0,(5:100.0,6:100.0):94.959999):100.0):53.3100=
01,(29:100.0,27:100.0,28:100.0,50:100.0,49:100.0):94.809998,(44:100.0,43:10=
0.0,48:100.0,45:100.0,46:100.0,47:100.0):99.459999):58.490002):51.580002):6=
1.540001):49.66);
+
+
+
+END;
diff -r 89dbce43ba88afdc3e6265feea7e7e042bb030a7 -r 75a03bacdc7a3dc5b1c03f8=
b02df0ab383366955 test-data/visualization/phyloviz/2_nexus.nex
--- /dev/null
+++ b/test-data/visualization/phyloviz/2_nexus.nex
@@ -0,0 +1,96 @@
+#NEXUS
+
+[!This data set was downloaded from TreeBASE, a relational database of phy=
logenetic knowledge. TreeBASE has been supported by the NSF, Harvard Univer=
sity, Yale University, SDSC and UC Davis. Please do not remove this acknowl=
edgment from the Nexus file.
+
+
+Generated on August 18, 2012; 12:14 GMT
+
+TreeBASE (cc) 1994-2008
+
+Study reference:
+Naish D., Dyke G., Cau A., & Escuilli=C3=A9 F. 2012. A gigantic bird from =
the Upper Cretaceous
+of Central Asia. Biology Letters, 8(1): 97-100.
+
+TreeBASE Study URI: http://purl.org/phylo/treebase/phylows/study/TB2:S130=
08]
+
+BEGIN TREES;
+ TITLE Imported_trees;
+ LINK TAXA =3D Taxa1;
+ TRANSLATE
+ 1 Herrerasaurus,
+ 2 Tawa,
+ 3 Allosaurus,
+ 4 Alvarezsaurus,
+ 5 Anchiornis,
+ 6 Archaeopteryx,
+ 7 Archaeorhynchus,
+ 8 Avimimus,
+ 9 Baryonyx,
+ 10 Beipiaosaurus,
+ 11 Caenagnathus,
+ 12 Caudipteryx,
+ 13 Ceratosaurus,
+ 14 Chirostenotes,
+ 15 Citipati,
+ 16 Compsognathus,
+ 17 Confuciusornis,
+ 18 Dilong,
+ 19 Dilophosaurus,
+ 20 Epidendrosaurus,
+ 21 Epidexipteryx,
+ 22 Erlicosaurus,
+ 23 Eustreptospondylus,
+ 24 Gallimimus,
+ 25 Garudimimus,
+ 26 Gobipteryx,
+ 27 Guanlong,
+ 28 Haplocheirus,
+ 29 Harpymimus,
+ 30 Hebeiornis,
+ 31 Hongshanornis,
+ 32 Huoshanornis,
+ 33 Iberomesornis,
+ 34 Ichthyornis,
+ 35 Incisivosaurus,
+ 36 Jeholornis,
+ 37 Limusaurus,
+ 38 Longicrusavis,
+ 39 Longipteryx,
+ 40 Longirostravis,
+ 41 Majungasaurus,
+ 42 Masiakasaurus,
+ 43 Monolophosaurus,
+ 44 Mononykus,
+ 45 Neornithes,
+ 46 Ornitholestes,
+ 47 Ornithomimus,
+ 48 Patagonykus,
+ 49 Patagopteryx,
+ 50 Pelecanimimus,
+ 51 Pengornis,
+ 52 Protarchaeopteryx,
+ 53 Protopteryx,
+ 54 Rinchenia,
+ 55 Sapeornis,
+ 56 Segnosaurus,
+ 57 Shenzhousaurus,
+ 58 Shuvuuia,
+ 59 Sinornithosaurus,
+ 60 Sinosauropteryx,
+ 61 Sinovenator,
+ 62 Sinraptor,
+ 63 Syntarsus_kayentakatae,
+ 64 Troodon,
+ 65 Tyrannosaurus,
+ 66 Velociraptor,
+ 67 Yanornis,
+ 68 Yixianornis,
+ 69 Zhongjianornis,
+ 70 Zhongornis,
+ 71 Zuolong,
+ 72 Samrukia;
+ TREE Figure_1A =3D [&R] (1,(2,(((((43,(3,62)),(71,((46,((((28,(4,(48=
,(44,58)))),((((5,(61,(64,(59,66)))),(6,((36,(55,(69,(((7,34,45,49,72,(31,3=
8),(67,68)),(33,((32,((26,30),(39,40))),(51,53)))),(17,70))))),(20,21)))),(=
(11,(12,(8,(14,(15,54))))),(35,52))),(10,(22,56)))),(50,(57,(29,(25,(24,47)=
))))),(16,60))),(27,(18,65))))),(9,23)),(13,(41,(37,42)))),(19,63))));
+
+
+
+END;
diff -r 89dbce43ba88afdc3e6265feea7e7e042bb030a7 -r 75a03bacdc7a3dc5b1c03f8=
b02df0ab383366955 test-data/visualization/phyloviz/3_phyloxml.xml
--- /dev/null
+++ b/test-data/visualization/phyloviz/3_phyloxml.xml
@@ -0,0 +1,257 @@
+<?xml version=3D"1.0" encoding=3D"UTF-8"?>
+<phyloxml xmlns:xsi=3D"http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation=3D"http://www.phyloxml.org http://www.phyloxml.org/1=
.10/phyloxml.xsd"
+ xmlns=3D"http://www.phyloxml.org">
+ <phylogeny rooted=3D"true">
+ <clade>
+ <clade>
+ <branch_length>0.18105</branch_length>
+ <confidence type=3D"unknown">89.0</confidence>
+ <clade>
+ <branch_length>0.07466</branch_length>
+ <confidence type=3D"unknown">32.0</confidence>
+ <clade>
+ <branch_length>0.26168</branch_length>
+ <confidence type=3D"unknown">100.0</confidence>
+ <clade>
+ <branch_length>0.22058</branch_length>
+ <confidence type=3D"unknown">89.0</confidence>
+ <clade>
+ <branch_length>0.28901</branch_length>
+ <confidence type=3D"unknown">100.0</confidence>
+ <clade>
+ <branch_length>0.06584</branch_length>
+ <confidence type=3D"unknown">100.0</confidence>
+ <clade>
+ <branch_length>0.02309</branch_length>
+ <confidence type=3D"unknown">43.0</confidenc=
e>
+ <clade>
+ <branch_length>0.0746</branch_length>
+ <confidence type=3D"unknown">100.0</confi=
dence>
+ <clade>
+ <branch_length>0.02365</branch_length>
+ <confidence type=3D"unknown">88.0</con=
fidence>
+ <clade>
+ <name>22_MOUSE</name>
+ <branch_length>0.05998</branch_leng=
th>
+ <taxonomy>
+ <code>MOUSE</code>
+ </taxonomy>
+ </clade>
+ <clade>
+ <name>Apaf-1_HUMAN</name>
+ <branch_length>0.01825</branch_leng=
th>
+ <taxonomy>
+ <code>HUMAN</code>
+ </taxonomy>
+ </clade>
+ </clade>
+ <clade>
+ <name>12_CANFA</name>
+ <branch_length>0.04683</branch_length>
+ <taxonomy>
+ <code>CANFA</code>
+ </taxonomy>
+ </clade>
+ </clade>
+ <clade>
+ <name>11_CHICK</name>
+ <branch_length>0.15226</branch_length>
+ <taxonomy>
+ <code>CHICK</code>
+ </taxonomy>
+ </clade>
+ </clade>
+ <clade>
+ <name>16_XENLA</name>
+ <branch_length>0.4409</branch_length>
+ <taxonomy>
+ <code>XENLA</code>
+ </taxonomy>
+ </clade>
+ </clade>
+ <clade>
+ <branch_length>0.17031</branch_length>
+ <confidence type=3D"unknown">100.0</confidence>
+ <clade>
+ <branch_length>0.10929</branch_length>
+ <confidence type=3D"unknown">100.0</confiden=
ce>
+ <clade>
+ <name>14_FUGRU</name>
+ <branch_length>0.02255</branch_length>
+ <taxonomy>
+ <code>FUGRU</code>
+ </taxonomy>
+ </clade>
+ <clade>
+ <name>15_TETNG</name>
+ <branch_length>0.09478</branch_length>
+ <taxonomy>
+ <code>TETNG</code>
+ </taxonomy>
+ </clade>
+ </clade>
+ <clade>
+ <name>17_BRARE</name>
+ <branch_length>0.1811</branch_length>
+ <taxonomy>
+ <code>BRARE</code>
+ </taxonomy>
+ </clade>
+ </clade>
+ </clade>
+ <clade>
+ <branch_length>0.01594</branch_length>
+ <confidence type=3D"unknown">53.0</confidence>
+ <clade>
+ <branch_length>0.10709</branch_length>
+ <confidence type=3D"unknown">68.0</confidence>
+ <clade>
+ <name>1_BRAFL</name>
+ <branch_length>0.26131</branch_length>
+ <taxonomy>
+ <code>BRAFL</code>
+ </taxonomy>
+ </clade>
+ <clade>
+ <name>18_NEMVE</name>
+ <branch_length>0.38014</branch_length>
+ <taxonomy>
+ <code>NEMVE</code>
+ </taxonomy>
+ </clade>
+ </clade>
+ <clade>
+ <name>23_STRPU</name>
+ <branch_length>0.48179</branch_length>
+ <taxonomy>
+ <code>STRPU</code>
+ </taxonomy>
+ </clade>
+ </clade>
+ </clade>
+ <clade>
+ <branch_length>0.34475</branch_length>
+ <confidence type=3D"unknown">100.0</confidence>
+ <clade>
+ <name>26_STRPU</name>
+ <branch_length>0.36374</branch_length>
+ <taxonomy>
+ <code>STRPU</code>
+ </taxonomy>
+ <sequence>
+ <domain_architecture length=3D"1319">
+ <domain from=3D"18" to=3D"98" confidence=3D"=
3.4E-5">Death</domain>
+ <domain from=3D"189" to=3D"481" confidence=
=3D"1.8E-10">NB-ARC</domain>
+ <domain from=3D"630" to=3D"668" confidence=
=3D"8.2E-5">WD40</domain>
+ </domain_architecture>
+ </sequence>
+ </clade>
+ <clade>
+ <name>25_STRPU</name>
+ <branch_length>0.33137</branch_length>
+ <taxonomy>
+ <code>STRPU</code>
+ </taxonomy>
+ <sequence>
+ <domain_architecture length=3D"1947">
+ <domain from=3D"143" to=3D"227" confidence=
=3D"7.4E-5">Death</domain>
+ <domain from=3D"227" to=3D"550" confidence=
=3D"2.0E-13">NB-ARC</domain>
+ <domain from=3D"697" to=3D"736" confidence=
=3D"7.9E-4">WD40</domain>
+ <domain from=3D"745" to=3D"785" confidence=
=3D"1.5">WD40</domain>
+ <domain from=3D"1741" to=3D"1836" confidence=
=3D"2.0">Adeno_VII</domain>
+ </domain_architecture>
+ </sequence>
+ </clade>
+ </clade>
+ </clade>
+ <clade>
+ <branch_length>1.31498</branch_length>
+ <confidence type=3D"unknown">100.0</confidence>
+ <clade>
+ <name>CED4_CAEEL</name>
+ <branch_length>0.13241</branch_length>
+ <taxonomy>
+ <code>CAEEL</code>
+ </taxonomy>
+ <sequence>
+ <domain_architecture length=3D"714">
+ <domain from=3D"7" to=3D"90" confidence=3D"9.2E=
-14">CARD</domain>
+ <domain from=3D"116" to=3D"442" confidence=3D"5=
.8E-151">NB-ARC</domain>
+ </domain_architecture>
+ </sequence>
+ </clade>
+ <clade>
+ <name>31_CAEBR</name>
+ <branch_length>0.04777</branch_length>
+ <taxonomy>
+ <code>CAEBR</code>
+ </taxonomy>
+ <sequence>
+ <domain_architecture length=3D"554">
+ <domain from=3D"1" to=3D"75" confidence=3D"0.00=
46">CARD</domain>
+ <domain from=3D"101" to=3D"427" confidence=3D"2=
.1E-123">NB-ARC</domain>
+ </domain_architecture>
+ </sequence>
+ </clade>
+ </clade>
+ </clade>
+ <clade>
+ <branch_length>0.13172</branch_length>
+ <confidence type=3D"unknown">45.0</confidence>
+ <clade>
+ <branch_length>0.24915</branch_length>
+ <confidence type=3D"unknown">95.0</confidence>
+ <clade>
+ <branch_length>0.76898</branch_length>
+ <confidence type=3D"unknown">100.0</confidence>
+ <clade>
+ <name>28_DROPS</name>
+ <branch_length>0.1732</branch_length>
+ <taxonomy>
+ <code>DROPS</code>
+ </taxonomy>
+ <sequence>
+ <domain_architecture length=3D"535">
+ <domain from=3D"112" to=3D"399" confidence=
=3D"1.4E-5">NB-ARC</domain>
+ </domain_architecture>
+ </sequence>
+ </clade>
+ <clade>
+ <name>Dark_DROME</name>
+ <branch_length>0.18863</branch_length>
+ <taxonomy>
+ <code>DROME</code>
+ </taxonomy>
+ <sequence>
+ <domain_architecture length=3D"1421">
+ <domain from=3D"108" to=3D"397" confidence=
=3D"2.1E-5">NB-ARC</domain>
+ </domain_architecture>
+ </sequence>
+ </clade>
+ </clade>
+ <clade>
+ <name>29_AEDAE</name>
+ <branch_length>0.86398</branch_length>
+ <taxonomy>
+ <code>AEDAE</code>
+ </taxonomy>
+ <sequence>
+ <domain_architecture length=3D"423">
+ <domain from=3D"109" to=3D"421" confidence=3D"9=
.3E-6">NB-ARC</domain>
+ </domain_architecture>
+ </sequence>
+ </clade>
+ </clade>
+ <clade>
+ <name>30_TRICA</name>
+ <branch_length>0.97698</branch_length>
+ <taxonomy>
+ <code>TRICA</code>
+ </taxonomy>
+ </clade>
+ </clade>
+ </clade>
+ </clade>
+ </phylogeny>
+</phyloxml>
diff -r 89dbce43ba88afdc3e6265feea7e7e042bb030a7 -r 75a03bacdc7a3dc5b1c03f8=
b02df0ab383366955 test-data/visualization/phyloviz/4_newick.nhx
--- /dev/null
+++ b/test-data/visualization/phyloviz/4_newick.nhx
@@ -0,0 +1,33 @@
+(((BGIOSIBCA028421_ORYSA:0.423485[&&NHX:S=3DORYSA:O=3DBGIOSIBCA028421.1:G=
=3DBGIOSIBCA028421],
+At5g41150_ARATH:0.273135[&&NHX:S=3DARATH:O=3DAt5g41150.1:G=3DAt5g41150]
+):0.690991[&&NHX:S=3DMagnoliophyta:D=3DN:B=3D100],
+(rad16_SCHPO:0.718598[&&NHX:S=3DSCHPO:O=3DSPCC970.01:G=3DSPCC970.01],
+RAD1_YEAST:1.05456[&&NHX:S=3DYEAST:O=3DYPL022W.1:G=3DYPL022W]
+):0.344838[&&NHX:S=3DAscomycota:D=3DN:B=3D100]
+):0.103849[&&NHX:S=3DEukaryota:D=3DN:B=3D61],
+((((((((ERCC4_HUMAN:0.067531[&&NHX:S=3DHUMAN:O=3DENST00000311895.3:G=3DENS=
G00000175595],
+Ercc4_MOUSE:0.17422[&&NHX:S=3DMOUSE:O=3DENSMUST00000023206.5:G=3DENSMUSG00=
000022545]
+):0.065513[&&NHX:S=3DEuarchontoglires:D=3DN:B=3D100],
+ENSMODT00000006086_MONDO:0.104633[&&NHX:S=3DMONDO:O=3DENSMODT00000006086.2=
:G=3DENSMODG00000004840]
+):0.083764[&&NHX:S=3DTheria:D=3DN:B=3D100],
+Q5ZJP8_CHICK:0.153132[&&NHX:S=3DCHICK:O=3DENSGALT00000004716.2:G=3DENSGALG=
00000002981]
+):0.057998[&&NHX:S=3DAmniota:D=3DN:B=3D100],
+ENSXETT00000024054_XENTR:0.288632[&&NHX:S=3DXENTR:O=3DENSXETT00000024054.2=
:G=3DENSXETG00000010991]
+):0.075713[&&NHX:S=3DTetrapoda:D=3DN:B=3D100],
+(zgc-63468_BRARE:0.2218[&&NHX:S=3DBRARE:O=3DENSDART00000015780.4:G=3DENSDA=
RG00000014161],
+NEWSINFRUT00000137921_FUGRU:0.220441[&&NHX:S=3DFUGRU:O=3DNEWSINFRUT0000013=
7921.3:G=3DNEWSINFRUG00000130312]
+):0.170605[&&NHX:S=3DClupeocephala:D=3DN:B=3D100]
+):0.238713[&&NHX:S=3DEuteleostomi:D=3DN:B=3D100],
+ENSCINT00000011737_CIOIN:0.623567[&&NHX:S=3DCIOIN:O=3DENSCINT00000011737.2=
:G=3DENSCING00000005673]
+):0.07499[&&NHX:S=3DChordata:D=3DN:B=3D100],
+(Sm00.scaff00195.0600_SCHMA:0.784609[&&NHX:S=3DSCHMA:O=3DSm00.scaff00195.0=
600:G=3DSm00.scaff00195.0600],
+(CBG03141_CAEBR:0.093703[&&NHX:S=3DCAEBR:O=3DCBG03141:G=3DCBG03141],
+NP_496498_CAEEL:0.212236[&&NHX:S=3DCAEEL:O=3DC47D12.8.1:G=3DC47D12.8]
+):1.47416[&&NHX:S=3DCaenorhabditis:D=3DN:B=3D94]
+):0.26906[&&NHX:S=3DBilateria:D=3DN:B=3D97]
+):0.071406[&&NHX:S=3DBilateria:D=3DN:B=3D1],
+(mei-9-RA_DROME:0.170289[&&NHX:S=3DDROME:O=3DCG3697-RA.3:G=3DCG3697],
+GA17620-PA_DROPS:0.154817[&&NHX:S=3DDROPS:O=3DGA17620-PA:G=3DGA17620]
+):0.818474[&&NHX:S=3DSophophora:D=3DN:B=3D100]
+):0
+)[&&NHX:S=3DEukaryota:D=3DN];
\ No newline at end of file
diff -r 89dbce43ba88afdc3e6265feea7e7e042bb030a7 -r 75a03bacdc7a3dc5b1c03f8=
b02df0ab383366955 test-data/visualization/phyloviz/5_newick.nhx
--- /dev/null
+++ b/test-data/visualization/phyloviz/5_newick.nhx
@@ -0,0 +1,1 @@
+(CAE_ELE_PORCN:0.303421 ,((((DRO_PER_PORCN:0.001000 ,DRO_PSE_PORCN:0.00100=
0 )67:0.141994 ,(DRO_ANA_PORCN:0.111899 ,(DRO_ERE_PORCN:0.030516 ,(DRO_MEL_=
PORCN:0.021127 ,DRO_SEC_PORCN:0.021127 )38:0.030516 )35:0.111899 )18:0.1419=
94 )16:0.162611 ,(DRO_WIL_PORCN:0.152225 ,(DRO_VIR_PORCN:0.085057 ,DRO_MOJ_=
PORCN:0.085057 )24:0.152225 )15:0.162611 )13:0.295081 ,(ANO_GAM_PORCN:0.287=
545 ,((CIO_INT_PORCN:0.100686 ,CIO_SAV_PORCN:0.100686 )19:0.275542 ,((LOA_L=
OA_PORCN:0.036278 ,BRU_MAL_PORCN:0.036278 )29:0.272631 ,(((((DAN_RER_PORCN:=
0.086499 ,((TAK_RUB_PORCN:0.032609 ,TET_NIG_PORCN:0.032609 )32:0.048864 ,(G=
AD_MOR_PORCN:0.039387 ,(ORY_LAT_PORCN:0.031729 ,(GAS_ACU_PORCN:0.021882 ,OR=
E_NIL_PORCN:0.021882 )37:0.031729 )34:0.039387 )28:0.048864 )27:0.086499 )2=
3:0.119618 ,(LAT_CHA_PORCN:0.099348 ,((XEN_LAE_PORCN:0.033333 ,XEN_TRO_PORC=
N:0.033333 )31:0.091250 ,(ANO_CAR_PORCN:0.086538 ,((MON_DOM_PORCN:0.014100 =
,(MAC_EUG_PORCN:0.005423 ,SAR_HAR_PORCN:0.005423 )57:0.014100 )42:0.062862 =
,(ORN_ANA_PORCN:0.057974 ,(GOR_GOR_PORCN:0.033876 ,(FEL_CAT_PORCN:0.022851 =
,(PRO_CAP_PORCN:0.019716 ,(CAV_POR_PORCN:0.018599 ,(ERI_EUR_PORCN:0.015518 =
,((DIP_ORD_PORCN:0.007231 ,(MUS_MUS_PORCN:0.001085 ,(RAT_NOR_PORCN:0.001000=
,CRI_GRI_PORCN:0.001000 )69:0.001085 )64:0.007231 )53:0.012954 ,(DAS_NOV_P=
ORCN:0.011362 ,(LOX_AFR_PORCN:0.010575 ,(CAL_JAC_PORCN:0.010332 ,(OCH_PRI_P=
ORCN:0.010063 ,(MIC_MUR_PORCN:0.009123 ,(SUS_SCR_PORCN:0.008880 ,(MYO_LUC_P=
ORCN:0.008460 ,((CAN_FAM_PORCN:0.005423 ,AIL_MEL_PORCN:0.005423 )58:0.00809=
3 ,((PTE_VAM_PORCN:0.006508 ,BOS_TAU_PORCN:0.006508 )55:0.007494 ,((SPE_TRI=
_PORCN:0.003254 ,TUP_BEL_PORCN:0.003254 )61:0.006929 ,((OTO_GAR_PORCN:0.001=
085 ,(ORY_CUN_PORCN:0.001000 ,TUR_TRU_PORCN:0.001000 )68:0.001085 )65:0.005=
965 ,(EQU_CAB_PORCN:0.003688 ,(MAC_MUL_PORCN:0.002711 ,(PAN_TRO_PORCN:0.001=
446 ,(HOM_SAP_PORCN:0.001085 ,(PON_ABE_PORCN:0.001000 ,NOM_LEU_PORCN:0.0010=
00 )70:0.001085 )66:0.001446 )63:0.002711 )62:0.003688 )60:0.005965 )56:0.0=
06929 )54:0.007494 )52:0.008093 )51:0.008460 )50:0.008880 )49:0.009123 )48:=
0.010063 )47:0.010332 )46:0.010575 )45:0.011362 )44:0.012954 )43:0.015518 )=
41:0.018599 )40:0.019716 )39:0.022851 )36:0.033876 )30:0.057974 )26:0.06286=
2 )25:0.086538 )22:0.091250 )21:0.099348 )20:0.119618 )17:0.214465 ,(BRA_FL=
O_PORCN:0.189220 ,SAC_KOW_PORCN:0.189220 )12:0.214465 )11:0.257058 ,(NEM_VE=
C_PORCN:0.246631 ,AMP_QUE_PORCN:0.246631 )9:0.257058 )8:0.266904 ,(TRI_CAS_=
PORCN:0.259494 ,(PED_HUM_PORCN:0.227009 ,(NAS_VIT_PORCN:0.160241 ,(API_MEL_=
PORCN:0.031851 ,(BOM_TER_PORCN:0.004808 ,BOM_IMP_PORCN:0.004808 )59:0.03185=
1 )33:0.160241 )14:0.227009 )10:0.259494 )7:0.266904 )6:0.272631 )5:0.27554=
2 )4:0.287545 )3:0.295081 )2:0.303421 )1:0.0001;
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: inithello: Fixed truncation of downloaded fasta files.
by Bitbucket 27 Aug '12
by Bitbucket 27 Aug '12
27 Aug '12
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/changeset/89dbce43ba88/
changeset: 89dbce43ba88
user: inithello
date: 2012-08-27 18:52:43
summary: Fixed truncation of downloaded fasta files.
affected #: 1 file
diff -r 90aa7ae565d60d38c90f444322a68b55fc895701 -r 89dbce43ba88afdc3e6265feea7e7e042bb030a7 lib/galaxy/jobs/deferred/genome_transfer.py
--- a/lib/galaxy/jobs/deferred/genome_transfer.py
+++ b/lib/galaxy/jobs/deferred/genome_transfer.py
@@ -115,15 +115,16 @@
files = tar.getmembers()
for filename in files:
z = tar.extractfile(filename)
- try:
- chunk = z.read( CHUNK_SIZE )
- except IOError:
- os.close( fd )
- log.error( 'Problem decompressing compressed data' )
- exit()
- if not chunk:
- break
- os.write( fd, chunk )
+ while 1:
+ try:
+ chunk = z.read( CHUNK_SIZE )
+ except IOError:
+ os.close( fd )
+ log.error( 'Problem decompressing compressed data' )
+ exit()
+ if not chunk:
+ break
+ os.write( fd, chunk )
os.write( fd, '\n' )
os.close( fd )
tar.close()
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: afgane: style: explicitly define a color for the masthead highlight (i.e., gradient top)
by Bitbucket 26 Aug '12
by Bitbucket 26 Aug '12
26 Aug '12
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/changeset/90aa7ae565d6/
changeset: 90aa7ae565d6
user: afgane
date: 2012-08-27 02:57:31
summary: style: explicitly define a color for the masthead highlight (i.e., gradient top)
affected #: 2 files
diff -r b1f2c51d6bd8d8b1aecce8f62304cc2df278ccec -r 90aa7ae565d60d38c90f444322a68b55fc895701 static/june_2007_style/blue_colors.ini
--- a/static/june_2007_style/blue_colors.ini
+++ b/static/june_2007_style/blue_colors.ini
@@ -55,6 +55,7 @@
peek_table_header=#023858
# Masthead
masthead_bg=#2C3143
+masthead_bg_highlight=#333
masthead_text=#eeeeee
masthead_bg_hatch=-
masthead_link=#eeeeee
diff -r b1f2c51d6bd8d8b1aecce8f62304cc2df278ccec -r 90aa7ae565d60d38c90f444322a68b55fc895701 static/june_2007_style/galaxy_bootstrap_variables.less
--- a/static/june_2007_style/galaxy_bootstrap_variables.less
+++ b/static/june_2007_style/galaxy_bootstrap_variables.less
@@ -144,7 +144,7 @@
// -------------------------
@navbarHeight: 32px;
@navbarBackground: @masthead_bg;
-@navbarBackgroundHighlight: @grayDark;
+@navbarBackgroundHighlight: @masthead_bg_highlight;
@navbarText: @grayLight;
@navbarLinkColor: @grayLight;
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: Do not use enable_tracks or enable_pages options anymore; visualizations and pages are enabled for all instances.
by Bitbucket 24 Aug '12
by Bitbucket 24 Aug '12
24 Aug '12
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/changeset/b1f2c51d6bd8/
changeset: b1f2c51d6bd8
user: jgoecks
date: 2012-08-25 00:43:33
summary: Do not use enable_tracks or enable_pages options anymore; visualizations and pages are enabled for all instances.
affected #: 3 files
diff -r 3d32fa091951e9aa72f3c69272960b3f6b648722 -r b1f2c51d6bd8d8b1aecce8f62304cc2df278ccec templates/root/history_common.mako
--- a/templates/root/history_common.mako
+++ b/templates/root/history_common.mako
@@ -218,7 +218,7 @@
%if for_editing:
<a href="${h.url_for( controller='tool_runner', action='rerun', id=data.id )}" target="galaxy_main" title='${_("Run this job again")}' class="icon-button arrow-circle tooltip"></a>
- %if app.config.get_bool( 'enable_tracks', False ) and data.ext in app.datatypes_registry.get_available_tracks():
+ %if data.ext in app.datatypes_registry.get_available_tracks():
<%
if data.dbkey != '?':
data_url = h.url_for( controller='tracks', action='list_tracks', dbkey=data.dbkey )
diff -r 3d32fa091951e9aa72f3c69272960b3f6b648722 -r b1f2c51d6bd8d8b1aecce8f62304cc2df278ccec templates/webapps/galaxy/base_panels.mako
--- a/templates/webapps/galaxy/base_panels.mako
+++ b/templates/webapps/galaxy/base_panels.mako
@@ -78,12 +78,10 @@
[ _('Data Libraries'), h.url_for( controller='/library', action='index') ],
None,
[ _('Published Histories'), h.url_for( controller='/history', action='list_published' ) ],
- [ _('Published Workflows'), h.url_for( controller='/workflow', action='list_published' ) ]
- ]
- if app.config.get_bool( 'enable_tracks', False ):
- menu_options.append( [ _('Published Visualizations'), h.url_for( controller='/visualization', action='list_published' ) ] )
- if app.config.get_bool( 'enable_pages', False ):
- menu_options.append( [ _('Published Pages'), h.url_for( controller='/page', action='list_published' ) ] )
+ [ _('Published Workflows'), h.url_for( controller='/workflow', action='list_published' ) ],
+ [ _('Published Visualizations'), h.url_for( controller='/visualization', action='list_published' ) ],
+ [ _('Published Pages'), h.url_for( controller='/page', action='list_published' ) ]
+ ]
tab( "shared", _("Shared Data"), h.url_for( controller='/library', action='index'), menu_options=menu_options )
%>
@@ -98,15 +96,13 @@
%>
## Visualization menu.
- %if app.config.get_bool( 'enable_tracks', False ):
- <%
- menu_options = [
- [_('New Visualization'), h.url_for( controller='/tracks', action='index' ) ],
- [_('Saved Visualizations'), h.url_for( controller='/visualization', action='list' ) ]
- ]
- tab( "visualization", _("Visualization"), h.url_for( controller='/visualization', action='list'), menu_options=menu_options )
- %>
- %endif
+ <%
+ menu_options = [
+ [_('New Visualization'), h.url_for( controller='/tracks', action='index' ) ],
+ [_('Saved Visualizations'), h.url_for( controller='/visualization', action='list' ) ]
+ ]
+ tab( "visualization", _("Visualization"), h.url_for( controller='/visualization', action='list'), menu_options=menu_options )
+ %>
## Cloud menu.
%if app.config.get_bool( 'enable_cloud_launch', False ):
@@ -155,8 +151,7 @@
menu_options.append( [ _('Logout'), app.config.remote_user_logout_href, "_top" ] )
else:
menu_options.append( [ _('Preferences'), h.url_for( controller='/user', action='index', cntrller='user', webapp='galaxy' ), "galaxy_main" ] )
- if app.config.get_bool( 'enable_tracks', False ):
- menu_options.append( [ 'Custom Builds', h.url_for( controller='/user', action='dbkeys' ), "galaxy_main" ] )
+ menu_options.append( [ 'Custom Builds', h.url_for( controller='/user', action='dbkeys' ), "galaxy_main" ] )
if app.config.require_login:
logout_url = h.url_for( controller='/root', action='index', m_c='user', m_a='logout', webapp='galaxy' )
else:
@@ -165,8 +160,7 @@
menu_options.append( None )
menu_options.append( [ _('Saved Histories'), h.url_for( controller='/history', action='list' ), "galaxy_main" ] )
menu_options.append( [ _('Saved Datasets'), h.url_for( controller='/dataset', action='list' ), "galaxy_main" ] )
- if app.config.get_bool( 'enable_pages', False ):
- menu_options.append( [ _('Saved Pages'), h.url_for( controller='/page', action='list' ), "_top" ] )
+ menu_options.append( [ _('Saved Pages'), h.url_for( controller='/page', action='list' ), "_top" ] )
menu_options.append( [ _('API Keys'), h.url_for( controller='/user', action='api_keys', cntrller='user', webapp='galaxy' ), "galaxy_main" ] )
if app.config.use_remote_user:
menu_options.append( [ _('Public Name'), h.url_for( controller='/user', action='edit_username', cntrller='user', webapp='galaxy' ), "galaxy_main" ] )
diff -r 3d32fa091951e9aa72f3c69272960b3f6b648722 -r b1f2c51d6bd8d8b1aecce8f62304cc2df278ccec universe_wsgi.ini.sample
--- a/universe_wsgi.ini.sample
+++ b/universe_wsgi.ini.sample
@@ -506,15 +506,6 @@
# Enable Galaxy to communicate directly with a sequencer
#enable_sequencer_communication = False
-# Enable Galaxy's built-in visualization module, Trackster.
-#enable_tracks = True
-
-# Enable Galaxy Pages. Pages are custom webpages that include embedded Galaxy items,
-# such as datasets, histories, workflows, and visualizations; pages are useful for
-# documenting and sharing multiple analyses or workflows. Pages are created using a
-# WYSIWYG editor that is very similar to a word processor.
-#enable_pages = True
-
# Enable authentication via OpenID. Allows users to log in to their Galaxy
# account by authenticating with an OpenID provider.
#enable_openid = False
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